题意:给出一个上限硬币数量s,给出n套硬币价值,求一套硬币能用不大于s数量的硬币组成从1开始连续的区间价值,其中,如果其最大值相同,输出数量小的,如果再相同,输出最大价值小的。
思路:背包。显然要枚举硬币价值。一开始思路是开bool数组记录能否达到,再开used数组记录达到当前总价值的最小所需硬币数量;后来发现只用used一个数组即可。后来参考了另一个人的写法发现还可以优化成完全背包的类似写法。下面贴优化前和后的代码。
#include <stdio.h>
#include <string.h>
#define INF 0x3fffffff
#define N 1005
int n,m,T;
int a[15],used[N];
int res[3],out[15];//0表示最优cover值,1表示硬币数量,2表示最大硬币面值
int main(){
//freopen("a.txt","r",stdin);
while(scanf("%d",&n) && n){
int i,j,max;
res[1] = res[2] = INF;
res[0] = 0;
scanf("%d",&T);
while(T--){
memset(used,0,sizeof(used));
scanf("%d",&m);
for(i = 1;i<=m;i++){
scanf("%d",&a[i]);
used[a[i]] = 1;
}
for(i = 1;i<=m;i++)
for(j = a[i]+1;j<=n*100;j++){
if(!used[j] && used[j-a[i]] && used[j-a[i]]<n){
used[j] = 1;
used[j] = used[j-a[i]]+1;
}else if(used[j-a[i]] && used[j-a[i]]<n && used[j-a[i]]+1<used[j])
used[j] = used[j-a[i]]+1;
}
max = 0;
for(i = 1;i<=n*100;i++){
if(!used[i])
break;
max++;
}
if(max>res[0] || (max==res[0]&&m<res[1]) || (max==res[0]&&m==res[1]&&a[m]<res[2])){
res[0] = max;
res[1] = m;
res[2] = a[m];
for(j = 1;j<=m;j++)
out[j] = a[j];
}
}
printf("max coverage = %d : ",res[0]);
for(i = 1;i<=res[1];i++)
printf("%d ",out[i]);
putchar('\n');
}
return 0;
}
used用n+1初始化,找最大cover数量时碰到n+1则停止。比较巧妙!
#include <stdio.h>
#include <string.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define INF 0x3fffffff
#define N 1005
int n,m,T;
int a[15],used[N];
int res[3],out[15];//0表示最优cover值,1表示硬币数量,2表示最大硬币面值
int main(){
freopen("a.txt","r",stdin);
while(scanf("%d",&n) && n){
int i,j,max;
res[1] = res[2] = INF;
res[0] = 0;
scanf("%d",&T);
while(T--){
for(i = 1;i<=100*n;i++)
used[i] = n+1;
used[0] = 0;
scanf("%d",&m);
for(i = 1;i<=m;i++)
scanf("%d",&a[i]);
for(i = 1;i<=m;i++)
for(j = a[i];j<=n*100;j++)
used[j] = min(used[j],used[j-a[i]]+1);
max = 0;
for(i = 1;i<=n*100;i++){
if(used[i] == n+1)
break;
max++;
}
if(max>res[0] || (max==res[0]&&m<res[1]) || (max==res[0]&&m==res[1]&&a[m]<res[2])){
res[0] = max;
res[1] = m;
res[2] = a[m];
for(j = 1;j<=m;j++)
out[j] = a[j];
}
}
printf("max coverage = %d : ",res[0]);
for(i = 1;i<=res[1];i++)
printf("%d ",out[i]);
putchar('\n');
}
return 0;
}