洛谷P1441 砝码称重
作者:互联网
给定n砝码,要求删掉m砝码,问怎么删,剩下的砝码保留的最多。
考虑原来的砝码一共可以称出多少种重量,再用dfs深搜,每次深搜删去那个重量,搜完后求出剩余的重量。
如果是1 2 2,则1,1+2,1+2+2||||2,1+2,1+2+2||||2,1+2,1+2+2 共9个数字,每次搜索的时候删去其所影响的总方案
另搜索1,则删去1,1+2,1+2+2
搜索2,则删去2,1+2,1+2+2。
但是如果样例中的m=1改为2.
则要删去1相关的数后再删去2相关的数字,1,1+2,1+2+2,2,1+2,1+2+2。
很遗憾,这种算法是错误的。QAQ
dfs仍然是倒着搜,但是搜完后对搜完的整体进行dp(01背包)。
设计一个flag储存在dfs过程中哪个被排除了。dfs完后调用dp:
DP:
除dp[0]=1,其他全部设为0,如果某个重量可以被砝码组合,那么这个重量-这个砝码的重量一定可以被组合。所以有了动态转移方程。
如果(flag[i]可用的话)
if (dp[j-weight[i]]==1) (j指当前搜到的重量,weight是这个砝码的质量) dp[j]=1;
最后找一下weight数组里有多少个。
#include <iostream> using namespace std; int a[21],weight[2001],m,n,b[21],sum,ans,cnt; void dp() { for (int i=1;i<=sum;i++) weight[i]=0; weight[0]=1; cnt=0; //initialize for (int i=1;i<=n;i++) { if (a[i]==0) for (int j=sum;j>=b[i];j--) if (weight[j-b[i]]!=0) weight[j]=1; } for (int i=1;i<=sum;i++) if (weight[i]) cnt++; if (cnt>ans) ans=cnt; return; } void dfs(int depth,int initial) { if (depth==m) {dp(); return;} else { for (int i=initial;i<=n;i++){ a[i]=1; dfs(depth+1,i+1); a[i]=0; } } } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>>n>>m; for (int i=1;i<=n;i++) {cin>>b[i]; sum+=b[i];} //记录了sum,这样dp时循环就方便一点了。 dfs(0,1); cout<<ans; }
标签:洛谷,weight,P1441,int,dfs,砝码,删去,dp,称重 来源: https://www.cnblogs.com/asanagiyantia/p/12109134.html