pta l3-1(凑零钱)

题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805054207279104

题意:给定n枚硬币的面值,需要支付金额m,求能否恰好支付,若能,输出最小序列,若不能输出No Solution

思路:很容易看出这是一个完全背包问题,把每枚硬币的体积视为其面值,价值也视为其面值,则题目就转换成在背包空间为m时能否刚好装满,用dp[i][j]表示前i枚硬币装在空间为j的背包中最大价值。但题目的难点在于需要输出最小序列,我们可以这样做,输入数据之后按降序排列,然后从i=1到i=n进行dp,然后输出从i=n到i=1回溯,这样的结果自然就是序列最小的。还有一点需要注意的就是:

           if(dp[j]<=dp[j-a[i]]+a[i])               

    dp[j]=dp[j-a[i]]+a[i],b[i][j]=true;

  这里必须是‘<=',这样才能保证序列最小。

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=10005;
 5 int a[maxn],dp[105],res[maxn],k,n,m;
 6 bool b[maxn][105];
 7 
 8 bool cmp(int x,int y){
 9     return x>y;
10 }
11 
12 int main(){
13     scanf("%d%d",&n,&m);
14     for(int i=1;i<=n;++i)
15         scanf("%d",&a[i]);
16     sort(a+1,a+n+1,cmp);
17     for(int i=1;i<=n;++i)
18         for(int j=m;j>=a[i];--j)
19             if(dp[j]<=dp[j-a[i]]+a[i])
20                 dp[j]=dp[j-a[i]]+a[i],b[i][j]=true;
21     if(dp[m]!=m)
22         printf("No Solution
");
23     else{
24         int v=m,t=n;
25         while(v){
26             if(b[t][v]){
27                 res[k++]=a[t];
28                 v-=a[t];
29             }
30             --t;
31         }
32         printf("%d",res[0]);
33         for(int i=1;i<k;++i)
34             printf(" %d",res[i]);
35         printf("
");
36     }
37     return 0;
38 }
原文地址:https://www.cnblogs.com/FrankChen831X/p/10609806.html