洛谷P4342/poj1179 Polygon
看到这种拆边成链的问题,第一反应就是区间dp.
这一题的难点在状态转移上。单纯储存最大值不能满足dp中最优子结构的性质。
从转移角度入手,发现最大值的来源可能是两个最大值相加,相乘,两个最小值的相乘(不过把这个最小值相乘的去掉好像对答案没有什么影响);
最小值的来源可能是两个最小值相加,相乘,或者最大值和最小值相乘(正负得负)。
根据这个想法,不难想出用 f[ i ][ j ][ 0 / 1 ]储存从 i 到 j 的最大值与最小值.
最后,把链拆开复制一倍,跑一下区间dp就可以在O(N3)的时间内求出答案了!
1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 #include <iostream>
5 using namespace std;
6 const int MAXN = 55;
7 const int INF = 0x3f3f3f3f;
8
9 int N;
10 int f[MAXN * 2][MAXN * 2][2];//1->max, 0->min
11 int W[MAXN * 2], opt[MAXN * 2];
12 //opt : 1.opt[i]->opt between i and i + 1;
13 // 2.0->'+', 1->'*';
14
15
16 int main()
17 {
18 //freopen("p4342.in", "r", stdin);
19 scanf("%d", &N);
20
21 char ch;
22 for(int i = 1; i <= N * 2; i++)
23 {
24 if(i % 2 == 1)
25 {
26 scanf(" %c", &ch);
27 opt[i / 2] = ch == 'x';
28 }
29 else
30 scanf(" %d", &W[i / 2]);
31 }
32
33 for(int i = N + 1; i <= 2 * (N + 1); i++)
34 {
35 W[i] = W[i - N];
36 opt[i - 1] = opt[i - N - 1];
37 }
38
39 //for(int i = 1; i <= 2 * N; i++)
40 // cout<<W[i]<<" ";
41
42 for(int i = 1; i <= 2 * N; i++)
43 for(int j = 1; j <= 2 * N; j++)
44 f[i][j][0] = INF, f[i][j][1] = -INF;
45
46 for(int i = 1; i <= 2 * N; i++)
47 f[i][i][1] = f[i][i][0] = W[i];
48
49 for(int len = 2; len <= N; len++)
50 for(int l = 1; l <= (2 * N - len + 1); l++)
51 {
52 int r = l + len - 1;
53 for(int k = l; k < r; k++)
54 {
55 if(opt[k] == 1)
56 {
57 f[l][r][0] = min(f[l][k][0] * f[k + 1][r][1], f[l][r][0]);
58 f[l][r][0] = min(f[l][k][1] * f[k + 1][r][0], f[l][r][0]);
59 f[l][r][0] = min(f[l][k][0] * f[k + 1][r][0], f[l][r][0]);
60 f[l][r][0] = min(f[l][k][1] * f[k + 1][r][1], f[l][r][0]);
61
62 f[l][r][1] = max(f[l][k][0] * f[k + 1][r][0], f[l][r][1]);
63 f[l][r][1] = max(f[l][k][1] * f[k + 1][r][1], f[l][r][1]);
64 }
65 else
66 {
67 f[l][r][0] = min(f[l][k][0] + f[k + 1][r][0], f[l][r][0]);
68 f[l][r][1] = max(f[l][k][1] + f[k + 1][r][1], f[l][r][1]);
69 }
70 }
71 }
72
73
74 int ans = -INF;
75 for(int i = 1; i <= N; i++)
76 ans = max(ans, f[i][i + N - 1][1]);
77 cout<<ans<<endl;
78 for(int i = 1; i <= N; i++)
79 if(f[i][i + N - 1][1] == ans)
80 cout<<i<<" ";
81 return 0;
82 }