HDU I love sneakers! (分组背包)

I love sneakers!

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 1   Accepted Submission(s) : 1
Problem Description
After months of hard working, Iserlohn finally wins awesome amount of scholarship. As a great zealot of sneakers, he decides to spend all his money on them in a sneaker store.
There are several brands of sneakers that Iserlohn wants to collect, such as Air Jordan and Nike Pro. And each brand has released various products. For the reason that Iserlohn is definitely a sneaker-mania, he desires to buy at least one product for each brand. Although the fixed price of each product has been labeled, Iserlohn sets values for each of them based on his own tendency. With handsome but limited money, he wants to maximize the total value of the shoes he is going to buy. Obviously, as a collector, he won’t buy the same product twice. Now, Iserlohn needs you to help him find the best solution of his problem, which means to maximize the total value of the products he can buy.
 
Input
Input contains multiple test cases. Each test case begins with three integers 1<=N<=100 representing the total number of products, 1 <= M<= 10000 the money Iserlohn gets, and 1<=K<=10 representing the sneaker brands. The following N lines each represents a product with three positive integers 1<=a<=k, b and c, 0<=b,c<100000, meaning the brand’s number it belongs, the labeled price, and the value of this product. Process to End Of File.
 
Output
For each test case, print an integer which is the maximum total value of the sneakers that Iserlohn purchases. Print "Impossible" if Iserlohn's demands can’t be satisfied.
 
Sample Input
5 10000 3 1 4 6 2 5 7 3 4 99 1 55 77 2 44 66
 
Sample Output
255
 
Source
2009 Multi-University Training Contest 13 - Host by HIT
 
 
 
分组背包问题,大意**要买鞋,有k种牌子,每种牌子至少买一双鞋子。每双鞋子有标价跟实际价值。求用m多的钱买最多价值的鞋。

 

其实我觉得这题的难点就在处理“至少”这点上面。

 

状态方程很多都能推出用 dp[k][m] 来表示 已经买了k种鞋 在有m钱状态下的 鞋的最大价值。

 

状态转移方程为

 

        for( k = 1 ; k <= K ; k++)

        {

            for( i = 0 ; i < num[k] ; i++)

            {

                for( j = mm ; j >= m[k][i].m ; j--)

                {

                    if(dp[k][j - m[k][i].m] != -1)

                        dp[k][j] = Max(dp[k][j] , dp[k][j - m[k][i].m] + m[k][i].v);

                    if(dp[k-1][j - m[k][i].m] != -1 )

                        dp[k][j] = Max(dp[k][j] , dp[k-1][j - m[k][i].m] + m[k][i].v);



                }

            }

        }

如果忽略了两个红色的判断句,大家都看得出这只是单纯的01背包且 没有条件限制,加了这两句就能实现至少了。理由如下

 

一开始我将dp[][]数组初始化为-1表示所有的数都不合法。大于0表示合法

然后将所有的 k = 0 dp[0][]置为0,这是为了 k = 1时能合法计算。

 

从状态方程中看出,当上一个状态值为-1时表示他不合法。所以当前状态没有计算的必要也不合法答案。

 

如果计算完第k类商品的取值后,所有的dp[k][]均为-1的时候,第k类表明没有一鞋被买。故所有状态都不合法,接下来的所有值也都将不合法。

 

在计算第k组商品的过程中,当某个-1变成一个非负数的时候,也就表明当前的第k种已经拿了第i件物品,所以变成合法答案了。

 

如此推下去,最后一个值dp[k][m],就是答案了。如果依然是-1,就输出impossible把。

 

 

#include<iostream>

#include<cstdio>

#include<cstring>



using namespace std;



int N,M,K;

int dp[15][10010];



struct node{

    int p;

    int v;

}shoes[15][110];



int main(){



    //freopen("input.txt","r",stdin);



    int num[15];

    while(~scanf("%d%d%d",&N,&M,&K)){

        memset(num,0,sizeof(num));

        int a,b,c;

        for(int i=0;i<N;i++){

            scanf("%d%d%d",&a,&b,&c);

            shoes[a][num[a]].p=b;

            shoes[a][num[a]].v=c;

            num[a]++;

        }

        memset(dp,-1,sizeof(dp));

        for(int i=0;i<=M;i++)

            dp[0][i]=0;

        for(int k=1;k<=K;k++)

            for(int i=0;i<num[k];i++)

                for(int j=M;j>=shoes[k][i].p;j--){

                    if(dp[k][j-shoes[k][i].p]!=-1)

                        dp[k][j]=max(dp[k][j],dp[k][j-shoes[k][i].p]+shoes[k][i].v);

                    if(dp[k-1][j-shoes[k][i].p]!=-1)

                        dp[k][j]=max(dp[k][j],dp[k-1][j-shoes[k][i].p]+shoes[k][i].v);

                    //注意这里的2个if的顺序,如果下面这个if在上面的话,当体积为0时,

                    //相当于,Max( dp[k][j], dp[k][j] + m[k][i].v); dp[k][j]的值很可能会被计算两次。

                    //比如我最后给的那个测试例子。输出会是3,不会是正确答案2.

                }

        if(dp[K][M]<0)

            printf("Impossible\n");

        else

            printf("%d\n",dp[K][M]);

    }

    return 0;

}

 

你可能感兴趣的:(love)