洛谷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 }
原文地址:https://www.cnblogs.com/wsmrxc/p/9028828.html