1. 程式人生 > 實用技巧 >Educational Codeforces Round 95 (Rated for Div. 2) C. Mortal Kombat Tower (DP)

Educational Codeforces Round 95 (Rated for Div. 2) C. Mortal Kombat Tower (DP)

  • 題意:你和基友兩人從左往右輪流打怪獸,強怪用\(1\)表示,垃圾用\(0\)表示,但基友比較弱,打不過強怪,碰到強怪需要用一次魔法,而你很強,無論什麼怪都能亂殺,基友先打,每人每次至少殺一個怪獸,最多殺兩個怪獸,問最少需要用多少次魔法能將怪獸全部打完.

  • 題解:由於在打怪的過程中,每個狀態都與之前息息相關,所以我們可以用dp來寫,\(dp[i][who]\),\(i\)表示第\(i\)個怪獸,\(who\)表示我或基友,因為基友先打,所以基友的前兩個狀態我們是確定的,即:\(dp[1][0]=a[1]\),\(dp[2][0]=a[1]+a[2]\),而我在第二個怪獸的狀態也是確定的\(dp[2][1]=a[1]\)

    ,我們從第三個怪獸開始轉移,每次我和基友都可以選擇殺一個或兩個怪獸,所以就會由兩個狀態轉移過來,因為我是無敵的,所以我的狀態就是\(dp[i][1]=min(dp[i-1][0],dp[i-2][0])\),基友的是\(dp[i][0]=min(dp[i-1][1]+a[i],dp[i-2][1]+a[i-1]+a[i])\).然後\(dp[n][0]\)\(dp[n][1]\)取個最小即可.

  • 程式碼:

    int t;
    int n;
    int a[N];
    int dp[N][2];
    
    int main() {
        //ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	t=read();
    	while(t--){
    		n=read();
    		for(int i=1;i<=n;++i){
    			a[i]=read();
    			dp[i][0]=INF;
    			dp[i][1]=INF;
    		}
    		dp[1][0]=a[1];
    		dp[2][0]=a[1]+a[2];
    		dp[2][1]=a[1];
    		for(int i=3;i<=n;++i){
    			dp[i][1]=min(dp[i-1][0],dp[i-2][0]);
    			dp[i][0]=min(dp[i-1][1]+a[i],dp[i-2][1]+a[i-1]+a[i]);
    		}
    		printf("%d\n",min(dp[n][0],dp[n][1]));
    	}
    
        return 0;
    }