算法竞赛进阶指南, 284 页, 区间DP
题目意思:
有 n个点,每点都有一个整数(正,负, 0都可能), 用 n 条边把 n个点连成一个环形, 每条边上
都有一个运算符(加号 或者 乘号)。现在任意删除一条边,剩下 n - 1 条边。加下来 进行 n - 1 步骤,每一步 ,玩家选择一条边,然后用该边两边的数值和边上的运算符运算,等到新的整数。然后替换原来的两个顶点和一条边。 依次操作,直到剩下最后一点。求这个数的最大值,还要输出,具体删除了哪些边能得到最大值(多个的话,按递增输出)
本题要点:
1、转态表示, f[L][R] 表示第 L个顶点到 第R个顶点合并为一个顶点后的最大值
g[L][R] 表示第 L个顶点到 第R个顶点合并为一个顶点后的最小值
2、转态转移:
因为两个区间的合并, 操作符可能是 加号 ‘+’ ,乘号 ‘’.
1) 如果操作符是 ‘+’
区间 [L, R]的最大值 = 左区间 [L, K] 的最大值 + 右区间 [K + 1, R] 的最大值 ;
区间 [L, R]的最小值 = 左区间 [L, K] 的最小值 + 右区间 [K + 1, R] 的最小值
2) 如果操作符是 '’
minL 表示 左区间 [L, K] 的最小值,
maxL 表示 左区间 [L, K] 的最大值
minR 表示 右区间 [K + 1, R] 的最小值,
maxR 表示 右区间 [K + 1, R] 的最大值
区间 [L, R]的最大值 = max{minL * minR, minL * maxR, maxL * minR, maxL * maxR}
区间 [L, R]的最大值 = min{minL * minR, minL * maxR, maxL * minR, maxL * maxR}
注意K 的取值范围 L <= K < R
3、 注意, “破环成链” 的方法:
开两倍的区间来模拟 环形
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int MaxN = 110, INF = 0x3f3f3f3f;
char op[MaxN];
int ver[MaxN];
int n;
int f[MaxN][MaxN]; // f[L][R] 表示第 L个顶点到 第R个顶点合并为一个顶点后的最大值
int g[MaxN][MaxN]; // g[L][R] 表示第 L个顶点到 第R个顶点合并为一个顶点后的最小值
int remove_edge[MaxN];
int remove_cnt;
int sort_4(int a, int b, int c, int d, int flag)
{
int num[4];
num[0] = a, num[1] = b, num[2] = c, num[3]