题意
传送门 POJ 1179
题解
枚举初始时删的边,将环拆成链。观察删边、缩点的过程,有明显的区间性质,考虑用区间 D P DP DP 求解。由于点权值可能出现负数,那么在状态转移求最大值的过程中,要考虑负负得正的情况。
d
p
[
i
]
[
j
]
[
2
]
dp[i][j][2]
dp[i][j][2] 代表区间
[
i
,
j
)
[i,j)
[i,j) 最终能得到的最大值(第三维为
1
1
1)、最小值(第三维为
0
0
0),设
o
p
op
op 为
+
+
+ 或
×
\times
× 运算,
i
d
id
id 为
0
0
0 或
1
1
1,则有递推式
{
d
p
[
i
]
[
j
]
[
0
]
=
m
a
x
i
<
k
<
j
{
d
p
[
i
]
[
k
]
[
i
d
]
o
p
d
p
[
k
]
[
j
]
[
i
d
]
}
d
p
[
i
]
[
j
]
[
1
]
=
m
i
n
i
<
k
<
j
{
d
p
[
i
]
[
k
]
[
i
d
]
o
p
d
p
[
k
]
[
j
]
[
i
d
]
}
\begin{cases} dp[i][j][0]=max_{i<k<j}\{dp[i][k][id]\ op\ dp[k][j][id]\}\\ dp[i][j][1]=min_{i<k<j}\{dp[i][k][id]\ op\ dp[k][j][id]\}\\ \end{cases}
{dp[i][j][0]=maxi<k<j{dp[i][k][id] op dp[k][j][id]}dp[i][j][1]=mini<k<j{dp[i][k][id] op dp[k][j][id]}
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 55
int n, v[maxn], id[maxn], res[maxn], dp[maxn][maxn][2];
char op[maxn];
int main()
{
while (~scanf("%d", &n))
{
for (int i = 0; i < n; i++)
{
scanf(" %c%d", op + i, v + i);
}
int mx = -inf, cnt = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
int k = j - i < 0 ? j - i + n : j - i;
id[k] = j;
}
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++)
{
dp[i][i + 1][0] = dp[i][i + 1][1] = v[id[i]];
}
for (int w = 2; w <= n; w++)
{
for (int i = 0; i + w <= n; i++)
{
int j = i + w, mx = -inf, mn = inf;
for (int k = i + 1; k < j; k++)
{
bool f = op[id[k]] == 't';
int x1 = dp[i][k][0], x2 = dp[i][k][1], x3 = dp[k][j][0], x4 = dp[k][j][1];
int a = f ? x1 + x3 : x1 * x3;
int b = f ? x1 + x4 : x1 * x4;
int c = f ? x2 + x3 : x2 * x3;
int d = f ? x2 + x4 : x2 * x4;
mx = max(mx, max(max(a, b), max(c, d))), mn = min(mn, min(min(a, b), min(c, d)));
}
dp[i][j][0] = mn, dp[i][j][1] = mx;
}
}
int tmp = dp[0][n][1];
if (tmp >= mx)
{
if (tmp > mx)
mx = tmp, cnt = 0;
res[cnt++] = i + 1;
}
}
printf("%d\n", mx);
for (int i = 0; i < cnt; i++)
{
printf("%d%c", res[i], i + 1 == cnt ? '\n' : ' ');
}
}
return 0;
}