題目大意:兩個人玩遊戲,一些牌排成一行,當前玩家可以從最左端或者最右端拿一張牌,第一個人永遠選擇最優的方案,第二個人總是貪心的拿當前牌堆左右兩端更大的,求最後第一個人拿的數字之和比第二個人大多少。
解題思路:題意和當時科創月賽的題很像,月賽時兩個人都是選擇最優方案。當時不懂dp(現在也只是初學),現在看來記憶化處理即可。對於每次拿牌,第一個人總是選擇最優方案,因此可以搜索一下,即左右都拿,遞歸,記錄下來;對於第二個人,只要枚舉兩種情況:左邊更大or右邊更大即可。這樣就是一個記憶化搜索的過程。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 1010;
int num[N];
long long dp[N][N];
long long compute(int l,int r)
{
if(dp[l][r]!=0){
//cout<<r<<" "<<l<<endl;
return dp[l][r];
}
if(r-l<=1){
//cout<<r<<" "<<l<<endl;
dp[l][r]=abs(num[r]-num[l]);
return dp[l][r];
}
else{
int ansl,ansr;
ansl=num[l],ansr=num[r];
if(num[l+1]>=num[r]){
ansl+=compute(l+2,r)-num[l+1];
}
else{
ansl+=compute(l+1,r-1)-num[r];
}
if(num[l]>=num[r-1]){
ansr+=compute(l+1,r-1)-num[l];
}
else{
ansr+=compute(l,r-2)-num[r-1];
}
dp[l][r]=max(ansl,ansr);
}
return dp[l][r];
}
int main()
{
int n;
int cnt=1;
while(~scanf("%d",&n) && n!=0){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
}
long long ans=compute(1,n);
printf("In game %d, the greedy strategy might lose by as many as %lld points.\n",cnt++,ans);
}
return 0;
}