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

题目描述
现有 n 个砝码,重量分别为a1a2a3an,在去掉 m 个砝码后,问最多能称量出多少不同的重量(不包括0)。
输入输出格式
输入格式:
输入文件weight.in的第1行为有两个整数 n m,用空格分隔
第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;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值