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

来源:互联网 发布:淘宝定价策略 编辑:程序博客网 时间:2024/05/22 17:23

题目描述
现有n个砝码,重量分别为a1a2a3an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0)。
输入输出格式
输入格式:
输入文件weight.in的第1行为有两个整数nm,用空格分隔
第2行有n个正整数a1a2a3an,表示每个砝码的重量。
输出格式:
输出文件weight.out仅包括1个整数,为最多能称量出的重量。
输入输出样例
输入样例#1:
3 1
1 2 2
输出样例#1:
3
说明
【样例说明】
在去掉一个重量为2的砝码后,能称量出123共3种重量。
【数据规模】
对于20%的数据,m=0
对于50%的数据,m1
对于50%的数据,n10
对于100%的数据,n20m4mnai100
解题报告
这道题我们要解决两个问题,一个是处理出去掉m个砝码有多少种方案,第二个是要在一个确定的方案上找出这个方案最多能称出多少重量不同的物品,也就是砝码组合起来有多少种重量不同的情况。
对于第一个问题,我们采用搜索的方法解决,我们的dfs有两个参数,分别是当前搜索到的位置(u)和已经去掉的砝码个数(step)。
有两个显然的终止条件,一个是step>m,另一个是u=n+1(u的初始值为1)。
一个搜索到的点u,他的下一个状态(u+1)有去掉它和不去掉它两种选项,由此我们就要分别写两个dfs分开搜索。
对于第二个问题,我们采用背包问题的解法来解决。也就是开一个dp[j],表示砝码重量总计为i时的方案是否可行。显然,dp[j]dp[ja[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;}
原创粉丝点击