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

来源:互联网 发布:电子商务网络拓扑图 编辑:程序博客网 时间:2024/05/18 00:25

多重背包,但是可以用完全背包来做。
参考: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[N];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]);    }}
阅读全文
0 0
原创粉丝点击