您的位置:首页 > 其它

poj 1787 Charlie's Change(完全背包 或 多重背包 记录路径)

2017-08-14 16:09 561 查看
多重背包,但是可以用完全背包来做。

参考:http://www.cnblogs.com/kuangbin/archive/2012/09/20/2695803.html

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 10010;
int dp[MAXN];
int path[MAXN];
int used[MAXN];
int P;
int v[4] = {1,5,10,25};
int num[4];
int res[100];

void init()
{
memset(res,0,sizeof(res));
memset(path,0,sizeof(path));
path[0] = -1;
for(int i = 1; i <= P; ++i)
dp[i] = -INF;
dp[0] = 0;
}

void solve()
{
for(int i = 0; i < 4; ++i)
{
memset(used,0,sizeof(used));
for(int j = v[i]; j <= P; ++j)
{
//dp[j-v[i]] >= 0如果不设这个条件。used会溢出
//而且dp[j-v[i]]<0的话,也没必要去更新,在这之前的状态组合不出来j-v[i]
if(dp[j-v[i]]+1 > dp[j] && dp[j-v[i]] >= 0 && used[j-v[i]] < num[i])
{
dp[j] = dp[j-v[i]]+1;
used[j] = used[j-v[i]]+1;
path[j] = j-v[i];
}
}
}
}

int main()
{
while(scanf("%d",&P))
{
scanf("%d %d %d %d",&num[0],&num[1],&num[2],&num[3]);
if(P+num[0]+num[1]+num[2]+num[3] == 0)
break;
init();
solve();
if(dp[P] != -INF)
{
while(path[P] != -1)
{
res[P-path[P]]++;
P = path[P];
}
printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",res[1],res[5],res[10],res[25]);
}
else
printf("Charlie cannot buy coffee.\n");
}
return 0;
}


多重背包:

参考:http://blog.csdn.net/libin56842/article/details/9470687

学到了记录一种多重背包记录路径的方法。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int N = 10010;
int dp[N*10];
int path
;
int cent[4] = {1,5,10,25};
int num[4];
int res[30];
int P;

void CompletePack(int pos)
{
for(int j = cent[pos]; j <= P; ++j)
{
if(dp[j-cent[pos]]+1 > dp[j])
{
dp[j] = dp[j-cent[pos]]+1;
path[j] = pos*N+j-cent[pos];
}
}
}

void ZeroOnePack(int pos, int k)
{
for(int j = P; j >= cent[pos]*k; --j)
{
if(dp[j-k*cent[pos]]+k > dp[j])
{
dp[j] = dp[j-k*cent[pos]]+k;
path[j] = pos*N+j-k*cent[pos];
}
}
}

void MultiplePack()
{
for(int i = 0; i < 4; ++i)
{
if(num[i]*cent[i] >= P)
CompletePack(i);
else
{
int temp = num[i];
for(int k = 1; k <= temp; k *= 2)
{
ZeroOnePack(i,k);
temp -= k;
}
if(temp) ZeroOnePack(i,temp);
}
}
}

int main()
{
int t;
while(scanf("%d",&P))
{
t = P;
for(int i = 0; i < 4; ++i)
{
scanf("%d",&num[i]);
t += num[i];
}
if(!t) break;
memset(path,0,sizeof(path));
memset(res,0,sizeof(res));
for(int i = 1; i <= P; ++i) dp[i] = -N;
dp[0] = 0;
MultiplePack();
if(dp[P] < 0)
{
printf("Charlie cannot buy coffee.\n");
continue;
}
while(P)
{
int s1 = path[P]/N;//s1表示货币的种类
int s2 = path[P]%N;//(P-s2)表示这种货币一共多少金额
res[cent[s1]] += (P-s2)/cent[s1];
P = s2;
}
printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",res[1],res[5],res[10],res[25]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: