POJ 1384 Piggy-Bank(完全背包)

POJ 1384 Piggy-Bank(完全背包)

http://poj.org/problem?id=1384

题意:

       现在有n种硬币,每种硬币有特定的重量cost[i] 克和它对应的价值val[i]. 每种硬币可以无限使用. 已知现在一个储蓄罐中所有硬币的总重量正好为m克, 问你这个储蓄罐中最少有多少价值的硬币? 如果不可能存在m克的情况, 那么就输出” This is impossible.”.

分析:

       由于每种硬币可以无限使用, 所以是明显的完全背包问题.

       本题的限制条件: 硬币总重量正好等于m.

       本题的目标条件: 硬币总价值尽量小.

       令dp[i][j]==x 表示只用前i种货币, 且当总重量达到j克时的最小价值和为x.

       初始化: 所有dp都为INF(无穷大), 且dp[0]==0. (因为本题的目标是价值最小,所以初始化为无穷大. 如果要让目标最大, 那么应该初始化为-1. )

       状态转移: dp[i][j] = min( dp[i-1][j] , dp[i][j-cost[i]]+val[i])

       上面方程前者表示第i种硬币一个都不选, 后者表示至少选1个第i种硬币.

       最终所求为dp[n][m]. (如果dp[n][m]==INF, 说明m克是一个不可达的状态)

       本题程序用的滚动数组, 所以dp只有[j]这一维.

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10000+5;
#define INF 1e9

int n;//货币种数
int m;//最大重量
int dp[maxn];
int cost[maxn];//每种货币重量
int val[maxn]; //每种货币价值

int main()
{
    int T; scanf("%d",&T);
    while(T--)
    {
        //读入数据
        int m1,m2;
        scanf("%d%d%d",&m1,&m2,&n);
        m=m2-m1;
        for(int i=1;i<=n;i++)
            scanf("%d%d",&val[i],&cost[i]);

        //初始化
        for(int i=0;i<=m;i++) dp[i]=INF;
        dp[0]=0;

        //递推过程
        for(int i=1;i<=n;i++)
        {
            for(int j=cost[i];j<=m;j++)
                dp[j] = min(dp[j], dp[j-cost[i]]+val[i]);
        }

        //输出结果
        if(dp[m]==INF) printf("This is impossible.\n");
        else printf("The minimum amount of money in the piggy-bank is %d.\n",dp[m]);
    }
    return 0;
}

你可能感兴趣的:(Algorithm,算法,dp,ACM)