洛谷砝码称重
题目链接:https://www.luogu.com.cn/problem/P1441
其实这道题是一个很令人匪夷所思的题,它的做法是dp+dfs,这是令人意外的,也是我见识短的暴露;
我们采取的策略是在n个数字中删除m个数的方式,并且从第一个数一一枚举
通过dfs过程找到一种状态以后,求出使用当前留下的这些砝码可以凑出多少个不同的重量,我们通过dp解决这个问题。
观察题目可得,这个过程可以通过01背包实现。
定义dp[i][j]为当前选取到了第j个砝码,如果通过之前的砝码可以称量出重量i那么f[i][j]的值为true。
状态转移方程为: dp[i][j]=dp[i-a[i]][j-1]
初始状态为dp[0][j]=true
最后dp[i][n]中true的个数就是通过这些砝码可以计算出的重量值。
通过滚动数组,我们可以只定义一个f[i]数组,降低了时间复杂度,注意此时内层循环倒序。
注意事项以及参考代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[30]; 4 bool vis[30]; 5 bool dp[9000]; 6 int ans; 7 int cnt; 8 int tot; 9 int n,m; 10 void DP() 11 { 12 memset(dp,0,sizeof(dp)); 13 cnt=0; 14 tot=0; 15 dp[0]=true; 16 for(register int i=1;i<=n;i++) 17 { 18 if(vis[i]) 19 continue; 20 for(register int j=tot;j>=0;j--) 21 { 22 if(dp[j]&&!dp[j+a[i]]) 23 { 24 dp[j+a[i]]=true; 25 cnt++; 26 } 27 } 28 tot+=a[i];//这个tot意为当前f[i]为真值的最大的i,极大加快了dp过程 29 } 30 ans=max(ans,cnt); 31 } 32 void dfs(int xuanqu,int ji) 33 { 34 if(ji>m) 35 return ; 36 if(xuanqu>n) 37 { 38 if(ji==m) 39 { 40 DP(); 41 42 } 43 return ;//return 44 } 45 dfs(xuanqu+1,ji);//选择当前的砝码 46 vis[xuanqu]=true;//标记 47 dfs(xuanqu+1,ji+1);//放弃当前的砝码 48 vis[xuanqu]=false;//回溯一部 49 } 50 int main() 51 { 52 ios::sync_with_stdio(false); 53 cin>>n>>m; 54 for(register int i=1;i<=n;i++) 55 cin>>a[i]; 56 dfs(1,0);//开始枚举 57 cout<<ans<<endl; 58 return 0; 59 }
本文来自博客园,作者:江上舟摇,转载请注明原文链接:https://www.cnblogs.com/LQS-blog/p/16029447.html