第一次写——
题意不再复述,(最近我一直在读题上犯错误..丢人)
明显的模型就是多重背包。注意了自己程序细节问题就很简单。
时间卡的紧一些,就用背包九讲上的01背包优化吧,可能是打印路径这里处理的不好,有500多ms
下次试试用单调队列优化。。
#include"stdio.h"
#include"stdlib.h"
#include"time.h"
#include"math.h"
#include"iostream"
#include"string.h"
#include"algorithm"
#include"vector"
#include"string"
#include"queue"
#include"map"
#define nmax 10000
#define vmax 11000
#define inf 0x7ffffff
#define eps 1e-8
#define PI 3.1415926535
#define PRIME 9999991
using namespace std;
int P;
int dp[vmax];
struct Pr{
int i,k;
int prv;
}pre[vmax];
int c[5];
int price[5];
///vars
void init_dp(){
int i;
for(i=0;i<=P;i++){
dp[i]=-inf;
}
}
inline int miny(int a,int b){return a<b?a:b;}
int main(){
//freopen("d:\\testdata.txt","r",stdin);
//freopen("d:\\spout1.txt","w",stdout);
//价格们:
price[0]=1;
price[1]=5;
price[2]=10;
price[3]=25;
while(scanf("%d%d%d%d%d",&P,&c[0],&c[1],&c[2],&c[3])==5&&P){
if(c[0]>=P){//小剪枝,没太大用
printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",P,0,0,0);
continue;
}
init_dp();
memset(pre,0,sizeof(pre));//指向上一个决策的数组
dp[0]=0;
int i,vi;
for(i=0;i<4;i++){//四种物品,i代表前i种
if(c[i]*price[i]>=P){
for(vi=price[i];vi<=P;vi++){
if(dp[vi]<dp[vi-price[i]]+1){
dp[vi]=dp[vi-price[i]]+1;
pre[vi].i=i;
pre[vi].k=1;
pre[vi].prv=vi-price[i];
}
}
}
else{
int k;
for(k=1;k<=c[i];k<<=1){
c[i]-=k;
int costi=price[i]*k;
int vali=k;
for(vi=P;vi>=costi;vi--){
if(dp[vi]<dp[vi-costi]+vali){
dp[vi]=dp[vi-costi]+vali;
pre[vi].i=i;
pre[vi].k=vali;
pre[vi].prv=vi-costi;
}
}
//printf("k=%d ",k);
}
int costi=price[i]*c[i];
int vali=c[i];
for(vi=P;vi>=costi;vi--){
if(dp[vi]<dp[vi-costi]+vali){
dp[vi]=dp[vi-costi]+vali;
pre[vi].i=i;
pre[vi].k=vali;
pre[vi].prv=vi-costi;
}
}
}
//if(dp[P]>0){break;}//这句话千万不能加。。。我当时犯傻了
}
int n[5];
memset(n,0,sizeof(n));
if(dp[P]>0){//数路径上的各种硬币用了多少个
int pi=P;
while(pi){
n[pre[pi].i]+=pre[pi].k;
pi=pre[pi].prv;
}
printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",n[0],n[1],n[2],n[3]);
}
else
printf("%s\n","Charlie cannot buy coffee.");
}
return 0;}