[hdu 3236] Gift Hunting

[hdu 3236] Gift Hunting

[hdu3236] Gift Hunting

(转自自己的CSDN博客)

一、题目描述

原题地址: http://acm.hdu.edu.cn/showproblem.php?pid=3236

GG有两张奖券,面额分别为V1、V2,准备给MM买礼物。当天是MM生日,所以MM还可以免费得到一份礼物。

礼物有价格和幸福值两个参数,并且礼物分为特殊礼物和普通礼物,特殊礼物是一定要全部到手的。

两张奖券不可以合并使用,、一种礼物也只能买一次。

问MM最大幸福值是多少,如果特殊礼物不能全部得到MM会不高兴,幸福值为-1。

二、题目分析

    比普通的二维背包问题多了两个设置,第一是MM可以免费得到一份礼物,第二是礼物分为特殊和普通两种。

1、特殊礼物是必买齐的,不管幸福值多少,所以要特殊处理一下。

2、用普通背包方法处理普通礼物。

3、由于还可以免费得到一份礼物,还需要一些小处理。

    用f[v1][v2][s]表示奖券V1,V2分别使用v1,v2时,且状态为s时候(s=1表示已经免费得到一份礼物了,s=0表示还木有免费得到礼物),MM的幸福值。

    对于普通礼物,状态转移方程:

f[v1][v2][1] = max( f[v1][v2][1], f[v1][v2][0] + Normal[k].happiness )

f[v1][v2][0] = max( f[v1][v2][0], f[v1 - Normal[k].price][v2][0] + Normal[k].happiness, f[v1][v2 - Norma[k].price][0] + Normal[k].happiness)

    对于特殊礼物,就是直接往里头一个一个礼物塞了。


代码:

hdu3236
#include <cstdio>
#include 
<cstdlib>

int const MAXN = 300;

struct gift {
    
int price, happiness;
}
 Special[MAXN],Normal[MAXN];

int V1, V2, Spe_Num, Nor_Num, Max_V1, Max_V2;
int f[500+100][50+10][2];    //f[v1][v2][s]奖券V1,V2用了v1 v2时的最大happy值,s=0表示还未使用Free 

bool Init();
bool Get_Special_Gift();     //fail --> return false;
int Get_Normal_Gift();

int main(){
    
int T = 0;
    
while (Init()){
        
++T;
        
if (Get_Special_Gift())
            printf(
"Case %d: %d\n\n", T, Get_Normal_Gift());
        
else
            printf(
"Case %d: -1\n\n", T);
    }

    
return 0;
}


bool Init(){
    
int n, i;
    
    scanf(
"%d%d%d"&V1, &V2, &n);
    
if (V1 == 0 && V2 == 0 && n == 0return false;

    Spe_Num 
= Nor_Num = 0;
    
for (i = 0; i < n; i++{
        
int P, H, S;
        scanf(
"%d%d%d"&P, &H, &S);
        
if (S == 1{
            Special[Spe_Num].price 
= P;
            Special[Spe_Num
++].happiness = H; 
        }

        
else {
            Normal[Nor_Num].price 
= P;
            Normal[Nor_Num
++].happiness = H;
        }

    }

    
return true;
}

            
bool Get_Special_Gift(){
    
int i,j,k,v1,v2,total, pre_total;
    
bool flag;
    
    
for (i = 0; i <= V1; i++)
        
for (j = 0; j <= V2; j++)
            
for (k = 0; k <= 1; k++
                f[i][j][k] 
= - 1;
    
    f[
0][0][0= total = 0;

    
for (k=0; k<Spe_Num; k++)
    
{
        pre_total 
= total;
        total 
+= Special[k].happiness;
        
for (v1=V1; v1>=0; v1--)
            
for (v2=V2; v2>=0; v2--{
                
if (f[v1][v2][1== pre_total)
                
{
                    
if (Special[k].price + v1 <= V1) f[Special[k].price + v1][v2][1= total;
                    
if (Special[k].price + v2 <= V2) f[v1][Special[k].price + v2][1= total;
                }

                
if (f[v1][v2][0== pre_total)
                
{
                    
if (Special[k].price + v1 <= V1) f[Special[k].price + v1][v2][0= total;
                    
if (Special[k].price + v2 <= V2) f[v1][Special[k].price + v2][0= total;
                    f[v1][v2][
1= total;
                }

            }

    }

    
    flag 
= false;

    
for (i = 0; i <= V1; i++)
        
for (j = 0; j <= V2; j++)
            
for (k = 0; k <= 1; k++{
                
if (f[i][j][k] != total) f[i][j][k] = - 1;
                
if (f[i][j][k] == total) flag =  true;
            }

                
    
return flag;
}


int Get_Normal_Gift(){
    
    
int v1,v2,s,k,ans = 0;
    
    
for (k=0; k<Nor_Num; k++)
        
for (v1 = V1; v1>=0; v1--)
            
for (v2 = V2; v2>=0; v2--){
                
for (s=0; s<=1; s++)
                    
if (f[v1][v2][s] != -1){
                        
if ( v1 + Normal[k].price<= V1 && f[v1][v2][s] + Normal[k].happiness > f[v1 + Normal[k].price][v2][s])
                            f[v1 
+ Normal[k].price][v2][s] = f[v1][v2][s] + Normal[k].happiness;
                        
if ( v2 + Normal[k].price<= V2 && f[v1][v2][s] + Normal[k].happiness > f[v1][v2 + Normal[k].price][s])
                            f[v1][v2 
+ Normal[k].price][s] = f[v1][v2][s] + Normal[k].happiness;
                    }

                
if (f[v1][v2][0!= -1 && f[v1][v2][0+ Normal[k].happiness > f[v1][v2][1])
                        f[v1][v2][
1= f[v1][v2][0+ Normal[k].happiness;
            }


    
for (v1 = V1; v1 >= 0; v1--)
        
for (v2 = V2; v2 >= 0; v2--)
            
for (s=0; s<=1; s++)
                
if (f[v1][v2][s] > ans) ans = f[v1][v2][s];
            
    
return ans;
}



写在最后:

个人感觉这应该是非常经典非常基础的二维背包的一个小小拓展,思路上来说还是比较简单的,不过DP写起来还是有一些需要注意的,譬如初始化、边界判断、还有避免物品重复获得某些变量应该用downto而不是to。

还有可以优化之处,譬如v1和v2其实不需要都从V1、 V2开始逆循环,可以设置Max_V1, Max_V2表示截止到上一个礼物最多使用V1和V2中的多少,然后v1和v2从Max_V1, Max_V2开始循环到0。
 

你可能感兴趣的:([hdu 3236] Gift Hunting)