1. 程式人生 > >D - FATE HDU-2159 FATE 二維背包

D - FATE HDU-2159 FATE 二維背包

text panel ret sub lin printf print %d tdi

D - FATE Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Status

Description

最近xhd正在玩一款叫做FATE的遊戲,為了得到極品裝備,xhd在不停的殺怪做任務。久而久之xhd開始對殺怪產生的厭惡感,但又不得不通過殺怪來升完這最後一級。現在的問題是,xhd升掉最後一級還需n的經驗值,xhd還留有m的忍耐度,每殺一個怪xhd會得到相應的經驗,並減掉相應的忍耐度。當忍耐度降到0或者0以下時,xhd就不會玩這遊戲。xhd還說了他最多只殺s只怪。請問他能升掉這最後一級嗎?

Input

輸入數據有多組,對於每組數據第一行輸入n,m,k,s(0 < n,m,k,s < 100)四個正整數。分別表示還需的經驗值,保留的忍耐度,怪的種數和最多的殺怪數。接下來輸入k行數據。每行數據輸入兩個正整數a,b(0 < a,b < 20);分別表示殺掉一只這種怪xhd會得到的經驗值和會減掉的忍耐度。(每種怪都有無數個)

Output

輸出升完這級還能保留的最大忍耐度,如果無法升完這級輸出-1。

Sample Input

10 10 1 10 1 1 10 10 1 9 1 1 9 10 2 10 1 1 2 2

Sample Output

0 -1 1 這個題目我先想直接通過自己的理解來解題,大概是標記一個數量,然後根據背包的情況不斷更改這個值的數量,只是中間的這種考慮針對有些情況是不合適的,所以經典的問題的一般性模擬,有時候還是有一些困難的。 這是錯誤的代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct dp_node
{
int value;
int total_num;
};

struct dp_node dp[105][105];
struct node
{
int tolerate;
int exp;
double rati;
friend bool operator<(node a,node b)
{
return a.rati>b.rati;
}
};

struct node num[105];


int main()
{
int n,m,k,s;
while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF)
{
for(int i=1;i<=k;i++)
{
scanf("%d%d",&num[i].exp,&num[i].tolerate);
num[i].rati=num[i].exp*1.0/num[i].tolerate;
}
// sort(num,num+k);

for(int j=0;j<105;j++)
{
dp[0][j].value=0;
dp[0][j].total_num=0;
dp[j][0].value=0;
dp[j][0].total_num=0;
}
for(int i=1;i<=k;i++)
{
for(int j=num[i].tolerate;j<=m;j++)
{
dp[i][j].value=dp[i-1][j].value;
dp[i][j].total_num=dp[i-1][j].total_num;
for(int ak=0;ak<=j/num[i].tolerate;ak++)
{
if(dp[i][j].value<dp[i-1][j-ak*num[i].tolerate].value+ak*num[i].exp)
{
dp[i][j].value=dp[i-1][j-ak*num[i].tolerate].value+ak*num[i].exp;
dp[i][j].total_num=dp[i-1][j-ak*num[i].tolerate].total_num+ak;
}

}
}
}
for(int i=0;i<=m;i++)
{
// printf("%d\n",dp[k][i].value);
if(dp[k][i].value>=n&&dp[k][i].total_num<=s)
{
printf("%d\n",m-i);
break;

}
if(i==m)
{
printf("-1\n");
}
}
}
return 0;
}

然後,後面用二維擴展背包,果然一下就過了,所以有時候,經典的問題,還是有其一般性與特點的。

這個的一般性主要體現在第二重循環中,通過這個循環很好的解決了一般性問題,同時也強掉了狀態轉移方程的重要性。

這時正確的代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int tolerate;
int exp;
double rati;
friend bool operator<(node a,node b)
{
return a.rati>b.rati;
}
};

struct node num[105];
int dp[105][105];

int main()
{
int n,m,k,s;
while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF)
{
for(int i=1;i<=k;i++)
{
scanf("%d%d",&num[i].exp,&num[i].tolerate);
num[i].rati=num[i].exp*1.0/num[i].tolerate;
}
memset(dp,0,sizeof(dp));
for(int i=1;i<=k;i++)
{
for(int j=num[i].tolerate;j<=m;j++)
{
for(int ak=1;ak<=s;ak++)
{
if(dp[j][ak]<dp[j-num[i].tolerate][ak-1]+num[i].exp)
dp[j][ak]=dp[j-num[i].tolerate][ak-1]+num[i].exp;
}
}
}
for(int i=0;i<=m;i++)
{
if(dp[i][s]>=n)
{
printf("%d\n",m-i);
break;
}
if(i==m)
printf("-1\n");
}

}
return 0;
}

D - FATE HDU-2159 FATE 二維背包