您的位置:首页 > 其它

UVa 10891 Game of Sum - 动态规划

2016-11-17 20:43 260 查看


  因为数的总和一定,所以用一个人得分越高,那么另一个人的得分越低。  

  用$dp[i][j]$表示从$[i, j]$开始游戏,先手能够取得的最高分。

  转移通过枚举取的数的个数$k$来转移。因为你希望先手得分尽量高,所以另一个人的最高得分应尽量少。

  $dp[i][j] = sum[i][j] - \min \{dp[i + k][j],dp[i][j - k]\}$

  但是发现计算$dp[i + k][j],dp[i][j - k]$的最小值的地方很重复,所以用一个$f[i][j]$储存前者的最优值,$g[i][j]$储存后者的最优值。

  这样就将代码的时间复杂度优化到O(n2)

Code

/**
* uva
* Problem#10891
* Accepted
* Time:0ms
*/
#include<iostream>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<sstream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
typedef bool boolean;
#define INF 0xfffffff
#define smin(a, b) a = min(a, b)
#define smax(a, b) a = max(a, b)
template<typename T>
inline void readInteger(T& u){
char x;
long long aFlag = 1;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
x = getchar();
aFlag = -1;
}
for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0');
ungetc(x, stdin);
u *= aFlag;
}

int n;
int *list;
int f[101][101];
int g[101][101];
int dp[101][101];

inline boolean init(){
readInteger(n);
if(n == 0)    return false;
list = new int[(const int)(n + 1)];
for(int i = 1; i <= n; i++){
readInteger(list[i]);
}
return true;
}

int *sum;
inline void getSum(){
sum = new int[(const int)(n + 1)];
sum[0] = 0;
for(int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + list[i];
}

inline void solve(){
memset(f, 0x7f, sizeof(f));
memset(g, 0x7f, sizeof(g));
for(int i = 1; i <= n; i++)    f[i][i] = g[i][i] = dp[i][i] = list[i];
for(int k = 1; k < n; k++){
for(int i = 1; i + k <= n; i++){
int j = i + k;
int m = 0;
smin(m, f[i + 1][j]);
smin(m, g[i][j - 1]);
dp[i][j] = sum[j] - sum[i - 1] - m;
f[i][j] = min(f[i + 1][j], dp[i][j]);
g[i][j] = min(g[i][j - 1], dp[i][j]);
}
}
printf("%d\n", dp[1]
* 2 - sum
);
delete[] list;
delete[] sum;
}

int main(){
while(init()){
getSum();
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: