涂色原题连接
缩点 + + +区间 d p dp dp — O ( n 2 ) O(n^2) O(n2)
缩点:
目的在于将一个连通块当成一个点方便处理。
区间 d p dp dp:
状态表示:
f ( i , j ) f(i, j) f(i,j);
含义:
表示在区间 [ i , j ] [i, j] [i,j]中选择起点,并将区间 [ i , j ] [i, j] [i,j]中的所有点染成同一种颜色的所有方案的集合;
集合属性:
操作次数的最小值;
状态计算:
① a [ i ] ! = a [ j ] a[i] != a[j] a[i]!=a[j]
-
若最后一次并入的点是 a [ i ] a[i] a[i]: f [ i ] [ j ] = f [ i + 1 ] [ j ] + 1 f[i][j] = f[i + 1][j] + 1 f[i][j]=f[i+1][j]+1;
-
若最后一次并入的点是 a [ j ] a[j] a[j]: f [ i ] [ j ] = f [ i ] [ j − 1 ] + 1 f[i][j] = f[i][j - 1] + 1 f[i][j]=f[i][j−1]+1;
故 f [ i ] [ j ] = m i n ( f [ i + 1 ] [ j ] , f [ i ] [ j − 1 ] ) + 1 f[i][j] = min(f[i + 1][j], f[i][j - 1]) + 1 f[i][j]=min(f[i+1][j],f[i][j−1])+1
② a [ i ] = = a [ j ] a[i] == a[j] a[i]==a[j]
-
若最后一次并入的点是 a [ i ] a[i] a[i]( a [ j ] a[j] a[j]在倒数第二次之前被并入): f [ i ] [ j ] ≥ f [ i + 1 ] [ j ] + 1 f[i][j] \ge f[i + 1][j] + 1 f[i][j]≥f[i+1][j]+1;
-
若最后一次并入的点是 a [ j ] a[j] a[j]( a [ i ] a[i] a[i]在倒数第二次之前被并入): f [ i ] [ j ] ≥ f [ i ] [ j − 1 ] + 1 f[i][j] \ge f[i][j - 1] + 1 f[i][j]≥f[i][j−1]+1;
-
若最后一次 a [ i ] a[i] a[i]与 a [ j ] a[j] a[j]被同时并入: f [ i ] [ j ] = f [ i + 1 ] [ j − 1 ] + 1 f[i][j] = f[i + 1][j - 1] + 1 f[i][j]=f[i+1][j−1]+1
故 f [ i ] [ j ] = f [ i + 1 ] [ j − 1 ] + 1 f[i][j] = f[i + 1][j - 1] + 1 f[i][j]=f[i+1][j−1]+1
J a v a Java Java 代码
import java.io.*;
public class Main {
static final int N = 5010;
static int[] a = new int[N];
static int[][] f = new int[N][N];
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().split(" ")[0]);
String[] s = br.readLine().split(" ");
//缩点
int cnt = 1;
for (int i = 1; i <= n; i ++) {
int x = Integer.parseInt(s[i - 1]);
if (x != a[cnt - 1]) a[cnt ++] = x;
}
n = cnt - 1;
//dp
for (int len = 2; len <= n; len ++) {
for (int i = 1; i + len - 1 <= n; i ++) {
int j = i + len - 1;
if (a[i] != a[j]) f[i][j] = Math.min(f[i + 1][j], f[i][j - 1]) + 1;
else f[i][j] = f[i + 1][j - 1] + 1;
}
}
System.out.print(f[1][n]);
}
}
区间 d p dp dp总结:
①枚举区间长度 l e n len len, l e n len len通常为 2 ∼ n 2\sim n 2∼n;
②枚举区间左端点(一般 i i i 从第一个元素开始,右端点 i + l e n − 1 i + len - 1 i+len−1 不能越界);
③进行决策:
- 若有区间分界点,则枚举分界点(一般左端点位置为第一个分界点,右端点上一个位置为最后一个分界点);
- 若不需要分界点,则直接进行决策。