Luogu P1441 砝码称重(fj省选)

 P1441 砝码称重

题目描述

现有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。

 

  这是福建省历届夏令营的题。。洛谷难度标签为提高+/省选-。。。

  这道题刚看没有思路,但只要跟你讲这是dfs+dp就会有思路了。。

 

  没错,这道题用dfs+dp。

  dfs 用来搜索每一种舍弃m个砝码后, 还有什么砝码是剩下的。

  dp用来求每一种舍弃m个砝码后,能量出种多少重量。

  dp[j]表示重量为j时,能否量出j。最后答案dp[j]里有多少个true

  相信大家已经心里有点底子了,看代码吧。

 1 #include <cstdio>
 2 #include <cstring>
 3 
 4 int f[2005], ans, a[25];
 5 int m, n, tf[25];
 6 
 7 int Max(int _a, int _b)
 8 {
 9     return ((_a > _b) ? _a : _b);
10 }
11 
12 void dp()
13 {
14     int ret, tot;    //ret是表示这种舍弃的情况 能量出多少不同的重量
15     memset(f, 0, sizeof(f));    //要记得每次重置。。。
16     ret = tot = 0;
17     f[0] = 1;
18     for(int i=1; i<=n; i++)
19     {
20         if(tf[i]) continue;        //如果这个砝码被舍弃了 就不考虑
21         for(int j=tot; j>=0; j--)
22         {
23             if(f[j] && !f[j+a[i]])    //能量出j的重量 且j+a[i]的重量未被量(防止ret重复自增)
24             {
25                 f[j+a[i]] = 1;
26                 ret++;
27             }
28         }
29         tot += a[i];    //表示前i个(不包括i)砝码能量出的最大重量 
30                         //这样每次就可以直接从背包能表示的最大重量开始算 速度会快很多
31                         //(跟题解dalao学的)
32     }
33     ans = Max(ans, ret);    //更新最大值
34 }
35 
36 void dfs(int dep, int now)    //dep是当前在考虑第dep个砝码 now为已经舍去的砝码数
37 {
38     if(now > m) return;        //如果舍弃的砝码大于m
39     if(dep > n+1) return;    //如果考虑的砝码超过n。。
40     if(dep == n+1)        //如果考虑完了所有砝码
41     {
42         if(now < m) return;    //如果舍弃的砝码小于m
43         if(now == m)        //考虑完所有砝码 且舍去了m个砝码 则dp()
44             dp();
45     }
46     dfs(dep+1, now);
47     tf[dep] = 1;    
48     dfs(dep+1, now+1);
49     tf[dep] = 0;        //记得状态要调回来
50 }
51 
52 int main()
53 {
54     scanf("%d%d", &n, &m);
55     for(int i=1; i<=n; i++)
56         scanf("%d", &a[i]);
57     dfs(1,0);
58     printf("%d", ans);
59     return 0;
60 }

 

转载于:https://www.cnblogs.com/yBaka/p/7747728.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值