uva 10891 Game of Sum (DP水题)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1832
博弈类的DP,通过枚举较短一段的最大得分推出较长一段的最大得分。转移方程是 dp[i][j] = sum[i][j] - min(dp[i][i], dp[i][i + 1], ... , dp[i][j - 1], dp[i + 1][j], dp[i + 2][j], ... ,dp[j][j])。
O(n^3)算法:
View Code
1 #define REP(i, n) for (int i = 0; i < (n); i++) 2 #define REP_1(i, n) for (int i = 1; i <= (n); i++) 3 4 int dp[N][N], sum[N]; 5 6 int main() { 7 int n; 8 while (~scanf("%d", &n) && n) { 9 sum[0] = 0; 10 REP_1(i, n) { 11 scanf("%d", &sum[i]); 12 sum[i] += sum[i - 1]; 13 } 14 _clr(dp); 15 REP_1(d, n) { 16 REP_1(i, n - d + 1) { 17 int j = i + d - 1, tmp = sum[j] - sum[i - 1]; 18 dp[i][j] = tmp; 19 REP(l, d - 1) { 20 dp[i][j] = max(dp[i][j], tmp - dp[i][i + l]); 21 dp[i][j] = max(dp[i][j], tmp - dp[j - l][j]); 22 } 23 } 24 } 25 // printf("%d %d\n", dp[1][n], sum[n] - dp[1][n]); 26 printf("%d\n", (dp[1][n] << 1) - sum[n]); 27 } 28 return 0; 29 }
在计算较短段的时候记录头尾的最小值,可以得到O(n^2)算法:
View Code
1 #define REP(i, n) for (int i = 0; i < (n); i++) 2 #define REP_1(i, n) for (int i = 1; i <= (n); i++) 3 4 int dp[N][N], sum[N], rec[2][N]; 5 6 int main() { 7 int n; 8 while (~scanf("%d", &n) && n) { 9 sum[0] = 0; 10 REP_1(i, n) { 11 scanf("%d", &sum[i]); 12 sum[i] += sum[i - 1]; 13 } 14 _clr(dp); 15 REP(i, 2) REP_1(j, n) rec[i][j] = inf; 16 REP_1(d, n) { 17 REP_1(i, n - d + 1) { 18 int j = i + d - 1, tmp = sum[j] - sum[i - 1]; 19 dp[i][j] = max(tmp, max(tmp - rec[0][i], tmp - rec[1][j])); 20 rec[0][i] = min(dp[i][j], rec[0][i]); 21 rec[1][j] = min(dp[i][j], rec[1][j]); 22 } 23 } 24 // printf("%d %d\n", dp[1][n], sum[n] - dp[1][n]); 25 printf("%d\n", (dp[1][n] << 1) - sum[n]); 26 } 27 return 0; 28 }
——written by Lyon