這題我自己感覺是一道很經典的DP題目,對於DP大神來說是非常裸的題,但是對於我這樣的DP初學者來說,我覺得是很好的一道入門題。。。收益匪淺。
題意:以魔獸爲背景,給定一個英雄,英雄要打倒一個boss,英雄初始的血量與魔法值都是100,boss的血量也是100,輸入n,t,p;分別表示英雄有n個技能,在每一輪雙方攻擊完後可以恢復t的魔法值,boss的攻擊力爲p。
後來n行每行兩個數ai,bi(大於0小於100),表示使用技能需要的魔法值與技能的傷害(必須至少有ai的魔法值才能發動相對應的技能)。英雄也有一個普通攻擊,不需要魔法值,傷害爲1;
在每一回閤中都是英雄先攻擊。問最少用多少回合可以打倒boss,如在打倒boss之前英雄先死了就輸出My god!
解法:因爲每次boss的傷害是固定的,所以英雄死的時間也是固定的,所以如果在那個時間內不能殺死boss,就My god了。因爲這題是師兄出的DP基礎題,所以一開始就認定用DP做了,建立的數組dp[i][j]意思是在i輪boss剩下j血量的情況下英雄最大的魔法值爲dp[j];(我一開始錯誤的想法是第i輪boss被扣了j血量的情況下英雄的最大魔法值dp[j],可惜錯了,不知道爲什麼,求大神解答。。。)這思路是看其他大神博客得出的。
因爲代碼沒有涉及到什麼算法,主要是推出那個蛋疼的狀態轉移方程,所以就沒有什麼註釋,也沒有什麼好說的。
網上面的DP講座都說,最重要是搞清楚問題的決策與狀態,這樣才能寫出狀態轉移方程。
所以小弟不才,就這題說說決策與狀態(如果有錯望各大神指出):
具體對照代碼。。。
狀態:boss剩下j血量的狀態;
決策:是否使用第K個技能使狀態變成:boss剩下j - skill[k].bi血量的狀態。;(當然是在能使用這技能的情況下,前面有if判斷)
而決策的判斷條件就是魔法值了。因爲在任何一個狀態下,魔法值越多,就對英雄越有利。
所以態轉移方程:dp[j - skill[k].bi] = max (dp[j - skill[k].bi],dp[j] - skill[k].ai + t);
#include <stdio.h>
#include <string.h>
typedef struct{
int ai;
int bi;
}node;
int max (int a,int b)
{
return a > b ? a : b ;
}
int main ()
{
node skill[110];
int n,t,q,i,j,k,p;
int dp[110];
while (scanf ("%d%d%d",&n,&t,&q))
{
p = 0;
if (n == 0 && t == 0 && q == 0)
break;
for (i = 1 ; i <= n ; i++)
scanf ("%d%d",&skill[i].ai,&skill[i].bi);
skill[0].ai = 0;
skill[0].bi = 1;
memset (dp,-1,sizeof(dp));
dp[100] = 100;
int time = (100 % q == 0) ? 100/q : 100 / q + 1 ;//英雄在time回合內要打到boss;
for (i = 1 ; i <= time ; i ++)
{
for (j = 1 ; j <= 100 ; j ++)
{
if (dp[j] == -1)
continue;
for (k = 0 ; k <= n ; k ++)
{
if (j <= skill[k].bi && dp[j] >= skill[k].ai)
{
printf ("%d\n",i);
p = 1;
break;
}
else if (j > skill[k].bi && dp[j] >= skill[k].ai)
{
dp[j - skill[k].bi] = max (dp[j - skill[k].bi],dp[j] - skill[k].ai + t);
if (dp[j + skill[k].bi] > 100)
dp[j + skill[k].bi] = 100;
}
}
if (p)
break;
}
if(p)
break;
}
if (!p)
printf ("My god\n");
}
}