P1441 【砝码称重】
传送门
题目描述
现有 n n 个砝码,重量分别为, a2 a 2 , a3 a 3 ,……, an a n ,在去掉 m m 个砝码后,问最多能称量出多少不同的重量(不包括)。
输入输出格式
输入格式:
输入文件 weight.in w e i g h t . i n 的第 1 1 行为有两个整数和 m m ,用空格分隔
第2行有个正整数 a1 a 1 , a2 a 2 , a3 a 3 ,……, an a n ,表示每个砝码的重量。
输出格式:
输出文件 weight.out w e i g h t . o u t 仅包括 1 1 个整数,为最多能称量出的重量。
输入输出样例
输入样例#1:
1 1
2 2
输出样例#1:
3 3
说明
【样例说明】
在去掉一个重量为的砝码后,能称量出 1 1 ,, 3 3 共种重量。
【数据规模】
对于 20 20 %的数据, m=0 m = 0 ;
对于 50 50 %的数据, m≤1 m ≤ 1 ;
对于 50 50 %的数据, n≤10 n ≤ 10 ;
对于 100 100 %的数据, n≤20 n ≤ 20 , m≤4 m ≤ 4 , m<n m < n , ai≤100 a i ≤ 100 。
现在小菜鸡爱上了发题解。
于是,今天小菜鸡要挑战一下新高度————发一篇难度为 提高+/省选- 的题解。
废话不多说,拿道题目先看题。
题目大意:从 n n 个砝码中选出个,能成量出最多重量。
可以将题目分两个部分:
第一个部分:搜索(dfs)
第二个部分: dp d p ( 01 01 背包)
AC A C 思路:
1.美好的开始,缺少不了输入
2.用 dfs d f s 解决 n n 选的问题
3.用 dp d p 解决能成量出最多重量的问题
上 AC A C 代码:
#include<cstdio>//调用 scanf和printf 的库
#include<cstring>//调用 memset 的库
const int mx=205;//定义常量mx
int n,m,maxx=0,ans=0;
int a[mx],b[mx],f[20010];
//定义变量和数组
void dp()//dp(01背包)
{
memset(f,0,sizeof(f)),f[0]=1;//初始化f,但f[0]=1,否则结果一定为0
int s=0;//定义一个变量s,做累加
for(int i=1;i<=n;i++)
{
if(b[i]==0)continue;//如果没选,不用再讨论了
for(int j=maxx;j>=a[i];j--)//从上往下放
{
if(f[j-a[i]]==1&&f[j]==0)s++,f[j]=1;//第一次出现,标记并累加
}
}
if(ans<s)ans=s;//更新ans
}
void dfs(int x,int k)//x选k
{
if(k==m)//选好,进入下一步dp
{
dp();
return ;//返回
}
if(x>n)return ;//如果x个超出n个,返回上一层
dfs(x+1,k);
b[x]=1;//选中
dfs(x+1,k+1);//选下一个
b[x]=0;//还原
}
int main()
{
memset(b,0,sizeof(b));//初始化b数组为0
scanf("%d %d",&n,&m),m=n-m;//n选n-m个
for(int i=1;i<=n;i++)scanf("%d",&a[i]),maxx+=a[i];
//美好的输入
dfs(1,0);//跑dfs
printf("%d",ans);//输出能成量出最多重量
return 0;
}