zoukankan      html  css  js  c++  java
  • CF1114D Flood Fill(DP)

    题目链接:CF原网

    题目大意:$n$ 个方块排成一排,第 $i$ 个颜色为 $c_i$。定义一个颜色联通块 $[l,r]$ 当且仅当 $l$ 和 $r$ 之间(包括 $l,r$)所有方块的颜色相同。现在你可以选定一个起始位置 $p$,每次将 $p$ 所在颜色联通块的所有方块颜色改成另一种。这个操作可能将两个颜色联通块合并成一个。问最少要多少步,能让 $[1,n]$ 变成一个颜色联通块。

    $1le n,c_ile 5000$。


    其实是个很水的区间DP啊……为什么会有同学说不做呢……

    毕竟我能在考场上想到的DP能是难题吗……

    根据定义,$p$ 所在的颜色联通块就是一个区间。而且这个区间只会往外扩张,不会往里收缩。

    那就轻松的DP了。

    首先把一开始就是联通块的压成一块,不影响答案,而且会使下面的DP更快。比如,$5 3 3 1 4 4 2 4$ 可以压缩成 $5 3 1 4 2 4$。

    (下面假设压缩后长度为 $m$)

    令 $dp_{l,r}$ 表示目前 $[l,r]$ 是包含起始位置的极长颜色联通块(也就是不被其它联通块包含),需要将 $[1,m]$ 变为同色的还需要的最小步数。

    起始状态:$dp_{1,m}=0$。

    答案是所有 $dp_{i,i}$ 的最小值。

    转移:如果一个联通块要变色,那么只有可能变成 $l-1$ 的颜色或者 $r+1$ 的颜色。

    $l eq 1$ 时,$dp_{l,r}=min(dp_{l,r},dp_{l-1,r}+1)$。

    $r eq m$ 时,$dp_{l,r}=min(dp_{l,r},dp_{l,r+1}+1)$。

    注意还要判断 $l-1$ 和 $r+1$ 颜色相同:

    $l eq 1,r eq m$ 且 $c_{l-1}=c_{r+1}$ 时,$dp_{l,r}=min(dp_{l,r},dp_{l-1,r+1}+1)$。

    时间复杂度 $O(n^2)$。

    代码中我用的是记忆化搜索。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=5050;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline int read(){
        char ch=getchar();int x=0,f=0;
        while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return f?-x:x;
    }
    int n,a[maxn],m,b[maxn],f[maxn][maxn];
    int solve(int l,int r){
        if(l==1 && r==m) return 0;
        if(f[l][r]) return f[l][r];
        int ans=INT_MAX;
        if(l!=1) ans=min(ans,solve(l-1,r));
        if(r!=m) ans=min(ans,solve(l,r+1));
        if(l!=1 && r!=m && b[l-1]==b[r+1]) ans=min(ans,solve(l-1,r+1));
        return f[l][r]=ans+1;
    }
    int main(){
        n=read();
        FOR(i,1,n){
            a[i]=read();
            if(a[i]!=a[i-1]) b[++m]=a[i];
        }
        int ans=INT_MAX;
        FOR(i,1,m) ans=min(ans,solve(i,i));
        printf("%d
    ",ans);
    }
    View Code
  • 相关阅读:
    Centos-ip配置详解
    Selenium-java-js操作日历
    Selenium-java-获取当前时间
    一起学ROS之启动文件及ROS命令汇总
    一起学ROS之通信机制
    一起学ORBSLAM2(1)跑通ORBSLAM2 ubuntu 14.04的运行
    高斯金字塔的思考
    ubuntu下opencv2.4.9和opencv3.1.0的使用
    一起学ROS之安装ROS(ubuntu+ros+opencv2.4.9+kinect V2 安装教程)
    动态规划解决分层图最短路径问题
  • 原文地址:https://www.cnblogs.com/1000Suns/p/10362068.html
Copyright © 2011-2022 走看看