Description
有n种硬币,面值分别为v1, v2, ..., vn,每种都有无限多。给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?输出硬币数目的最小值和最大值。
Input
第一行两个整数,n,S(1≤n≤100, 0≤S≤100000)。
第二行n个整数vi-1...n(1≤vi≤S)。
Output
第一行两个整数,分别表示硬币数目的最小值 a 和最大值 b 。无解则输出 -1 。
第二行 a 个整数分别表示使用的是第几种硬币。
第三行 b 个整数分别表示使用的是第几种硬币。
Sample Input
6 12
1 2 3 4 5 6
Sample Output
2 12
6 6
1 1 1 1 1 1 1 1 1 1 1 1
Hint
样例是特殊的,编号和面值是相同的。你编写程序的时候要注意输出编号而不是面值。
结果按编号升序输出字典序小一种。
Source
入门经典,DP,DAG
Solution
考虑DP。
对于每个值i(1<=i<=s),我们可以枚举j,使得i从i-v[j]增加一个v[j]得来。因此,我们有了下面的代码片段:
for(register int i=1; i<=s; i++) { for(register int j=1; j<=n; j++) { if(i-v[j]<0) { continue; } else { if(mi[i]>mi[i-v[j]]+1) { mi[i]=mi[i-v[j]]+1; pi[i]=i-v[j]; } if(mx[i]<mx[i-v[j]]+1) { mx[i]=mx[i-v[j]]+1; px[i]=i-v[j]; } } } }
这样一来,题目就迎刃而解了!
Code
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 inline int read() 6 { 7 int f=1,x=0; 8 char c=getchar(); 9 10 while(c<'0' || c>'9') 11 { 12 if(c=='-')f=-1; 13 c=getchar(); 14 } 15 16 while(c>='0' && c<='9') 17 { 18 x=x*10+c-'0'; 19 c=getchar(); 20 } 21 22 return f*x; 23 } 24 25 int s1,n,v[105],s,a,b,ma,mb,d[100005],mi[100005],mx[100005],pi[100005],px[100005]; 26 int an[100005]; 27 28 int main() 29 { 30 n=read(),s=read(); 31 32 for(register int i=1; i<=n; i++) 33 { 34 v[i]=read(); 35 36 d[v[i]]=i; 37 } 38 39 for(register int i=1; i<=s; i++) 40 { 41 mi[i]=1000000007;//组成值i最少需要多少枚硬币 42 mx[i]=-1000000007;//组成值i最多需要多少枚硬币 43 } 44 45 mi[0]=0; 46 mx[0]=0; 47 48 for(register int i=1; i<=s; i++) 49 { 50 for(register int j=1; j<=n; j++) 51 { 52 if(i-v[j]<0) 53 { 54 continue; 55 } 56 else 57 { 58 if(mi[i]>mi[i-v[j]]+1) 59 { 60 mi[i]=mi[i-v[j]]+1; 61 62 pi[i]=i-v[j]; 63 } 64 65 if(mx[i]<mx[i-v[j]]+1) 66 { 67 mx[i]=mx[i-v[j]]+1; 68 69 px[i]=i-v[j]; 70 } 71 } 72 } 73 } 74 75 if(mi[s]==1000000007 || mx[s]==-1000000007)//如果组成不了s 76 { 77 printf("-1");//输出无解 78 79 return 0; 80 } 81 82 printf("%d %d ",mi[s],mx[s]);//输出最小组成数 83 //输出方案 84 s1=s; 85 86 int T=0; 87 88 memset(an,0,sizeof(an)); 89 90 while(s1>0) 91 { 92 an[++T]=d[s1-pi[s1]]; 93 94 s1=pi[s1]; 95 } 96 97 sort(an+1,an+1+T); 98 99 for(register int i=1; i<=T; i++) 100 { 101 printf("%d ",an[i]); 102 } 103 104 puts(""); 105 106 s1=s; 107 108 T=0; 109 110 memset(an,0,sizeof(an)); 111 112 while(s1>0) 113 { 114 an[++T]=d[s1-px[s1]]; 115 116 s1=px[s1]; 117 } 118 119 sort(an+1,an+1+T); 120 121 for(register int i=1; i<=T; i++) 122 { 123 printf("%d ",an[i]); 124 } 125 126 return 0;//结束 127 }