链接:戳这里
This is a two player game. Initially there are n integer numbers in an array and players A and B get
chance to take them alternatively. Each player can take one or more numbers from the left or right end
of the array but cannot take from both ends at a time. He can take as many consecutive numbers as
he wants during his time. The game ends when all numbers are taken from the array by the players.
The point of each player is calculated by the summation of the numbers, which he has taken. Each
player tries to achieve more points from other. If both players play optimally and player A starts the
game then how much more point can player A get than player B?
Input
The input consists of a number of cases. Each case starts with a line specifying the integer n (0 <
n ≤ 100), the number of elements in the array. After that, n numbers are given for the game. Input is
terminated by a line where n = 0.
Output
For each test case, print a number, which represents the maximum difference that the first player
obtained after playing this game optimally.
Sample Input
4
4 -10 -20 7
4
1 2 3 4
0
Sample Output
7
10
题意:给出一段序列,A,B两个人玩游戏,A先取。每次玩家取得时候必须是从左端或者右端取任意个数量,但是不能两端都取。所有数都被取完游戏结束,最后统计A B分别取得总数作为各自得分,两人得分都要尽量大,两个人每次都是最优取,要求A-B最大值
思路:序列的总和是一定的sum, x+y=sum 求(x-y)max =>(2*x-sum)max
我们设dp(i,j)表示每次玩家取得最大分,其实也可以相反的理解,留给对手最少
状态转移时,我们要枚举是从左边还是右边取,以及取多少个,等价于是取[k,j](i<k<=j)还是[i,k](i<=k<j)
dp(i,j)=sum(i,j)-min(dp(i+1,j),dp(i+2,j)....dp(j,j),0,dp(i,j-1),dp(i,j-2)....dp(i,i)) sum表示区间和 0表示整段区间都取
最后的答案也就是2*dp(1,n)-sum(1,n)
给出两种思路 一种是记忆化搜索 还有一种是递推
说实话 理解起来真的不是想的那么容易,感觉挺费劲的啊 ,看了代码摸出来的,要自己想还是需要时间的
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
int n;
int a[110],s[1001];
int vis[1001][1001],dp[1001][1001];
int DP(int l,int r){
if(vis[l][r]) return dp[l][r];
vis[l][r]=1;
int mn=0;
for(int i=l;i<r;i++) mn=min(mn,DP(l,i));
for(int i=l+1;i<=r;i++) mn=min(mn,DP(i,r));
dp[l][r]=s[r]-s[l-1]-mn;
return dp[l][r];
}
int main(){
while(scanf("%d",&n)!=EOF){
if(n==0) break;
mst(s,0);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),s[i]=s[i-1]+a[i];
mst(vis,0);
printf("%d\n",2*DP(1,n)-s[n]);
}
return 0;
}
另外一种的实现都写在代码里了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
int n;
int a[110];
int f[1001][1001],g[1001][1001],dp[10|01][1001],sum[1001];
/*
f(i,j)=min{d(i,j),d(i+1,j),....,d[j,j]}
g(i,j)=min{d(i,j),d(i,j-1),....,d(i,i)}
d(i,j)=sum[i,j]-min(f[i+1][j],g[i][j-1],0);
f(i,j)=min(f(i+1,j),dp(i,j));
g(i,j)=min(g(i,j-1),dp(i,j));
*/
int main(){
while(scanf("%d",&n)!=EOF){
if(n==0) break;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
for(int i=1;i<=n;i++) dp[i][i]=f[i][i]=g[i][i]=a[i];
for(int L=1;L<n;L++){
for(int i=1;i+L<=n;i++){
int j=i+L;
int mn=0;
mn=min(mn,min(f[i+1][j],g[i][j-1]));
dp[i][j]=sum[j]-sum[i-1]-mn;
f[i][j]=min(dp[i][j],f[i+1][j]);
g[i][j]=min(dp[i][j],g[i][j-1]);
}
}
printf("%d\n",2*dp[1][n]-sum[n]);
}
return 0;
}