题目大意:给定一个数列,两人轮流取数,只能从两端取,第一个取的人可以用任何策略,第二个贪心,问结束时第一个人会赢多少分。
题目分析:第一个人采用动态规划的方法,一定能最大化地赢第二个使用贪心的人。
思路:使用Bottom-Up的动态规划,,复杂度O(n2)。
状态:dp[i][j] = data[i...j]第一个人比第二个人赢多少
边界:if(i==j) dp[i][j] = -data[i]; //最后只剩一个人,一定是第二个人选
状态转移方程:
(1)第一个人拿:max{ data[left]+剩数组中能赢最多, data[right]+剩余数组中能赢最多}
if((j-i+1)==0)
dp[i][j] = max( data[i]+dp[i+1][j], data[j]+dp[i][j-1]);
(2)第二个人拿:选左右两边中最大的一个,如果左右相等,则选择左边
if(data[i]>=data[j])
dp[i][j] = -data[i] + dp[i+1][j];
else
dp[i][j] = -data[j] + dp[i][j-1];
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
int dp[1002][1002];
int data[1002];
using namespace std;
int main()
{
int n;
int count=0;
while(cin >> n && n)
{
count++;
for(int i=0;i<n;i++)
cin >> data[i];
for(int i=0;i<n;i++) //边界条件
dp[i][i]=-data[i];
for(int i=n-1;i>=0;i--){
for(int j=i+1;j<n;j++){
if((j-i+1)%2){
if(data[i]>=data[j])
dp[i][j] = -data[i]+dp[i+1][j];
else
dp[i][j] = -data[j]+dp[i][j-1];
}
else
dp[i][j] = max(data[i]+dp[i+1][j],data[j]+dp[i][j-1]);
}
}
cout << "In game " << count << ", the greedy strategy might lose by as many as " << dp[0][n-1] << " points." << endl;
}
return 0;
}