题目链接:http://lightoj.com/volume_showproblem.php?problem=1031
题目描述:
给出一个数列,两人轮流取数, 取完结束。每次可以取好多个数,但是只能从首或者尾为起点取连续的若干个。问最后两者取数和的绝对值最大为多少?
区间dp;
这道题我是在看了几份阶梯报告之后才想通的,现在想想很符合动态规划的要求
d(i, j)表示取数的人在数组i 到 j中能取的的最大值,然后中间枚举分割点,
ans = max(ans, sum[k]-sum[i-1]-d(k+1, j));
ans = max(ans, sum[j]-sum[k-1]-d(i, k-1));
采用和记忆化搜索的方式
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <vector> 7 #include <ctime> 8 #include <queue> 9 #include <list> 10 #include <set> 11 #include <map> 12 using namespace std; 13 #define INF 0x3f3f3f3f 14 typedef long long LL; 15 16 int a[110], sum[110], dp[110][110]; 17 int solve(int l, int r) 18 { 19 if(dp[l][r] != -1 * INF) 20 return dp[l][r]; 21 int res = sum[r]-sum[l-1]; 22 for(int i = l; i <= r; i++) 23 { 24 res = max(res, sum[i]-sum[l-1]-solve(i+1, r)); 25 res = max(res, sum[r]-sum[i-1]-solve(l, i-1)); 26 } 27 dp[l][r] = res; 28 return res; 29 } 30 int main() 31 { 32 int t, n; 33 scanf("%d", &t); 34 for(int ca = 1; ca <= t; ca++) 35 { 36 scanf("%d", &n); 37 sum[0] = 0; 38 for(int i = 1; i <= n; i++) 39 for(int j = i; j <= n; j++) 40 dp[i][j] = -1*INF; 41 for(int i = 1; i <= n; i++) 42 { 43 scanf("%d", &a[i]); 44 dp[i][i] = a[i]; 45 sum[i] = sum[i-1] + a[i]; 46 } 47 printf("Case %d: %d\n", ca, solve(1, n)); 48 } 49 return 0; 50 }