Luogu P1441 砝码称重(fj省选)

Posted yBaka

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }

 

以上是关于Luogu P1441 砝码称重(fj省选)的主要内容,如果未能解决你的问题,请参考以下文章

luogu P1441状压DP砝码称重

luogu P1441状压DP砝码称重

P1441 砝码称重

P1441 砝码称重

P1441 砝码称重

P1441 砝码称重(搜索+队列dp)