1. 程式人生 > >HDU 2159 FATE

HDU 2159 FATE

its 個數 正在 尋找 沒有 code 遍歷 升級問題 nbsp

FATE

  最近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

解題思路:
  本題要求處理殺怪升級問題,有多組數據,每組第一行給出4個整數,分別為升級所需的經驗n,忍耐度(體力)m,怪物種類k,最多殺怪數s,之後k行跟隨,每行輸入兩個整數,分別為殺掉這種怪會得到的經驗值,殺掉這種怪消耗的體力。要求輸出升完級後能保留的最大體力。

  基本思路為完全背包,用數組dp記錄消耗每個數量的體力所能獲得的最大經驗值,dp2記錄該種情況下的殺怪數。根據dp與dp2尋找答案。

  根據描述可以寫出動態轉移方程:

    dp[ j ] = max(dp[ j ], dp[ j - engn[ i ] ] + expn[ i ] )

    if(dp[ j ] == dp[ j - engn[ i ] ] + expn[ i ] )

      dp2[ j ] = dp2[ j - eng[ i ] ] + 1

  之後遍歷最大體力值找到獲得經驗值可以達到升級要求且殺怪數低於限制的體力消耗值最小值,並用最大體力值減去它便可以得到答案,若沒有符合要求的情況輸出-1。

 1 #include <bits/stdc++.h>
 2 using namespace
std; 3 const int maxn = 1e2+10; 4 int engn[maxn]; 5 int expn[maxn]; 6 int dp[maxn], dp2[maxn]; 7 int main() 8 { 9 int n, m, k, s; 10 while(scanf("%d%d%d%d", &n, &m, &k, &s) != EOF){ 11 //輸入升級經驗,忍耐度,怪物種類,最多殺怪數 12 for(int i = 1; i <= k; i++){ 13 scanf("%d%d", &expn[i], &engn[i]); 14 //輸入每種怪物經驗值與消耗忍耐度 15 } 16 for(int i = 0; i <= m; i++){ 17 //初始dp與dp2為0 18 dp[i] = dp2[i] = 0; 19 } 20 for(int i = 1; i <= k; i++){ //完全背包 21 for(int j = engn[i]; j <= m; j++){ //正向遍歷背包容量 22 dp[j] = max(dp[j], dp[j - engn[i]] + expn[i]); //動態轉移方程 23 if(dp[j] == dp[j - engn[i]] + expn[i]){ 24 dp2[j] = dp2[j - engn[i]] + 1; 25 } 26 } 27 } 28 int ans = -1; //初始化答案為-1 29 for(int i = 1; i <= m; i++){ 30 if(dp[i] >= n && dp2[i] <= s){ //找到符合升級條件與殺怪條件的消耗值 31 ans = m - i; //記錄最大剩余忍耐度 32 break; 33 } 34 } 35 printf("%d\n", ans); 36 } 37 return 0; 38 }

HDU 2159 FATE