区间DP
http://www.lightoj.com/volume_showproblem.php?problem=1031
给你n个数,A、B两个人从两端取数,每一次可以取连续的一段数,而且每个人都按让自己最优的方案去取数(即取的数的和尽可能大)
问最后A与B的差值最大是多少
解法:枚举区间长度,从小区间DP到大区间
对于一段区间,枚举分隔点,要么取左边,要么取右边
下面是两种写法
View Code
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int inf = ~0u>>2; int sum[110]; int dp[110][110]; inline int max(int a,int b){ return a>b?a:b; } int main() { int t,n,ca=1; scanf("%d",&t); while(t--) { scanf("%d",&n); sum[0]=0; memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) { scanf("%d",&sum[i]); dp[i][i]=sum[i]; sum[i]+=sum[i-1]; } for(int len=1;len<n;len++) { for(int i=1;i+len<=n;i++) { dp[i][i+len]=sum[i+len]-sum[i-1];//必须先让dp数组有个初状态 for(int j=i;j<i+len;j++) { dp[i][i+len]=max(dp[i][i+len],sum[j]-sum[i-1]-dp[j+1][i+len]); dp[i][i+len]=max(dp[i][i+len],sum[i+len]-sum[j]-dp[i][j]); } } } printf("Case %d: %d\n",ca++,dp[1][n]); } return 0; }
View Code
#include<stdio.h> #include<string.h> const int inf = ~0u>>2; int sum[110]; int dp[110][110]; inline int max(int a,int b){ return a>b?a:b; } int DP(int l,int r){ int &ret = dp[l][r]; if(ret!=-inf) return ret; ret=sum[r]-sum[l-1]; for(int m=l;m<r;m++){ ret=max(ret,sum[m]-sum[l-1]-DP(m+1,r)); ret=max(ret,sum[r]-sum[m]-DP(l,m)); } return ret; } int main(){ int t,n,ca=1; scanf("%d",&t); while(t--){ scanf("%d",&n); sum[0]=0; for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++) dp[i][j]=-inf; for(int i=1;i<=n;i++) { scanf("%d",&sum[i]); dp[i][i]=sum[i]; sum[i]+=sum[i-1]; } printf("Case %d: %d\n",ca++,DP(1,n)); } return 0; }