涂色题解(区间dp)

涂色原题连接

缩点 + + +区间 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][j1]+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][j1])+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][j1]+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][j1]+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][j1]+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 2n;

②枚举区间左端点(一般 i i i 从第一个元素开始,右端点 i + l e n − 1 i + len - 1 i+len1 不能越界);

③进行决策:

  • 若有区间分界点,则枚举分界点(一般左端点位置为第一个分界点,右端点上一个位置为最后一个分界点);
  • 若不需要分界点,则直接进行决策。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辞寒oo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值