1. 程式人生 > >hdu 6199 dp

hdu 6199 dp

題意:巨毒。。實際上就是A,B都希望自己得到的最多。前一個人拿k個,下一個人能拿k or k+1

思路:倒著DP。。實際上兩個人是同一種策略,那麼其實一個dp陣列就可以了。。從最後一步拿k個往回推,dp[i][j]表示取第i個時候拿走包含i的j個,轉移方程dp[i][j]=sum[i+j-1]-sum[i-1]-max(dp[i+j][j],dp[i+j][j+1]) (PS,注意一下邊界的合法性判斷),轉移的時候要減去上一步的最優解。。因為每一步對手都會選擇最優策略。。

PS。這個題卡空間。。。要麼只開一個數組,要麼迴圈滾動一下

程式碼:

#include<bits/stdc++.h>
#define MEM(x) memset(x,0,sizeof(x))
using namespace std;
int dp[22000][205],n,sum[22010],v[22010];
int main(){
	int t;
	scanf("%d", &t);
	while (t--){
		scanf("%d",&n);
        sum[0]=0;
        MEM(dp);MEM(sum);
        for(int i=1;i<=n;++i)scanf("%d",&v[i]),sum[i]=sum[i-1]+v[i];
        if(n==1){
             printf("%d\n",v[1]);
             continue;
        }
        int lim = 200;
        for(int i=n;i>=1;--i){
            for(int j =1;j<=lim;++j){
                if(i+j-1>n) break;
                int sub=-2e9;
                dp[i][j]=sum[i+j-1]-sum[i-1];
                if(i+j+j-1<=n)sub=max(dp[i+j][j],sub);
                if(i+j+j<=n)sub=max(dp[i+j][j+1],sub);
                if(sub!=-2e9) dp[i][j]-=sub;
            }
        }
        printf("%d\n", max(dp[1][1],dp[1][2]));
	}
	return 0;
}