题意:
就是找出来一个字典序最小的硬币集合,且这个硬币集合里面所有硬币的值的和等于题目中的M
题解:
01背包加一下记录路径,如果1硬币不止一个,那我们也不采用多重背包的方式,把每一个1硬币当成一个独立的单位来进行01背包dp
但是我们知道背包dp的路径可能不止一条,而我们要从中得到字典序最小的序列,我的代码中两次不同的排序会得到最大/小字典序
降序 == 最小字典序
升序 == 最大字典序
1 #include<iostream> 2 #include<queue> 3 #include<vector> 4 #include<string.h> 5 #include<stdio.h> 6 #include<algorithm> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=5e4+10; 10 const int N=1e4+10; 11 int v[N]; 12 int vv[N]; 13 int dp[N]; 14 bool pre[N][105]; 15 int main() 16 { 17 int m,n; 18 scanf("%d%d",&n,&m); 19 for(int i=1; i<=n; i++) 20 { 21 scanf("%d",&v[i]); 22 } 23 sort(v+1,v+n+1); //从大到小排序那么答案输出就是最小字典序,如果是从小到大排序,那么答案输出 24 //就是最大字典序(这就是结论),greater<int>() 25 memset(dp,0,sizeof(dp)); 26 memset(pre,0,sizeof(pre)); 27 for(int i=1; i<=n; i++) 28 { 29 for(int j=m; j>=v[i]; j--) 30 { 31 if(dp[j]<=dp[j-v[i]]+v[i]) 32 { 33 dp[j]=dp[j-v[i]]+v[i]; 34 pre[i][j]=1;//如果第i个歌曲被放进背包,,标记当前背包的位置,记录路径; 35 } 36 } 37 } 38 if(dp[m]!=m) 39 { 40 printf("No Solution "); 41 return 0; 42 } 43 int i=n,j=m,flag=0; //这里的初赋值可不能随意改(控制输出最后最大/小字典序就是sort排序和这里,至于为什么可以画一下图) 44 while(i>=1&&j>=0) 45 { 46 if(pre[i][j]) 47 { 48 if(!flag) 49 printf("%d",v[i]),flag=1; 50 else printf(" %d",v[i]); 51 j=j-v[i];//第i张歌曲放在了第当背包容量为j-v[i]时,下一步找第i-1张歌曲.(由此的来dp[j]=dp[j-v[i]]+v[i];) 52 } 53 i--; 54 } 55 return 0; 56 }
我对多重背包记录路径和完全背包记录路径
1、对于多重背包记录路径
第一种方法就是像这一道题一样,把多重背包当作01背包来写,但是这样时间复杂度肯定高
2、完全背包都不限制数量了,那记录路径就没有意义了