您的位置:首页 > 其它

LuoguP1441 砝码称重 解题报告【搜索+背包型DP】

2017-10-25 20:03 330 查看
题目描述

现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0)。

输入输出格式

输入格式:

输入文件weight.in的第1行为有两个整数n和m,用空格分隔

第2行有n个正整数a1,a2,a3,……,an,表示每个砝码的重量。

输出格式:

输出文件weight.out仅包括1个整数,为最多能称量出的重量。

输入输出样例

输入样例#1:

3 1

1 2 2

输出样例#1:

3

说明

【样例说明】

在去掉一个重量为2的砝码后,能称量出1,2,3共3种重量。

【数据规模】

对于20%的数据,m=0;

对于50%的数据,m≤1;

对于50%的数据,n≤10;

对于100%的数据,n≤20,m≤4,m<n,ai≤100。

解题报告

这道题我们要解决两个问题,一个是处理出去掉m个砝码有多少种方案,第二个是要在一个确定的方案上找出这个方案最多能称出多少重量不同的物品,也就是砝码组合起来有多少种重量不同的情况。

对于第一个问题,我们采用搜索的方法解决,我们的dfs有两个参数,分别是当前搜索到的位置(u)和已经去掉的砝码个数(step)。

有两个显然的终止条件,一个是step>m,另一个是u=n+1(u的初始值为1)。

一个搜索到的点u,他的下一个状态(u+1)有去掉它和不去掉它两种选项,由此我们就要分别写两个dfs分开搜索。

对于第二个问题,我们采用背包问题的解法来解决。也就是开一个dp[j],表示砝码重量总计为i时的方案是否可行。显然,dp[j]从dp[j−a[i]]转移过来。

这样一来,剩下的就很明朗了:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=20,M=2000;
int n,m,a[N+5],vmax,ans;
bool dp[M+5],flag[N+5];
void dfs(int u,int step)
{
if(step>m)return ;
if(u==n+1)
{
if(step==m)
{
int tot=0;
for(int i=1;i<=vmax;i++)dp[i]=false;
for(int i=1;i<=n;i++)
{
if(flag[i])continue;
for(int j=vmax;j>=a[i];j--)
if(dp[j-a[i]])dp[j]=true;
}
for(int i=1;i<=vmax;i++)if(dp[i])tot++;
ans=max(ans,tot);
}
return ;
}
dfs(u+1,step);
flag[u]=1;
dfs(u+1,step+1);
flag[u]=0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),vmax+=a[i];
dp[0]=true;
dfs(1,0);
printf("%d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: