Codeforces1114 D. Flood Fill (DP)(整个区间染成同色)

题意:连续的几个颜色相同的格子称为一个连通块。选一个点为起点,每个操作是把所在连通块变一个颜色,求把整个区间染成同色需要的最少操作数。(注意,每次只能改变所在连通块的颜色,不能任选连通块,除了最开始时)

题解:

对于区间[L,R],最优的方案要么是全变成L处的颜色,要么全变成R处的颜色

因为可以看作是先选一个格子为起点,然后不断地将当前所在联通块与相邻格子合并,合并后一定是相邻格子的颜色才最优

那么,设f(i,j,0/1)表示区间[i,j]变为i/j处的颜色的最少操作次数

f(i,j,0)由f(i+1,j,0/1)转移来,f(i,j,1)由f(i,j-1,0/1)转移来,转移附加个颜色是否相同就行了,见代码。

#include<bits/stdc++.h>
using namespace std ;
#define ll long long
int a[5001],dp[5001][5001][2];
int main()
{
    int n;
    scanf("%d",&n);
    int cnt=0;
    for(int i=1 ; i<=n ; i++)
    {
        int x; scanf("%d",&x);
        if(x!=a[cnt])
        {
            a[++cnt]=x;
        }
    }
    n=cnt;
    for(int k=2 ; k<=n ; k++)
    {
        for(int i=1 ; i<=n ; i++)
        {
            int j=i+k-1;
            if(j>n) break;
            dp[i][j][0] = min(dp[i+1][j][0]+(a[i]!=a[i+1]) , dp[i+1][j][1]+(a[i]!=a[j]));
            dp[i][j][1] = min(dp[i][j-1][0]+(a[i]!=a[j]) , dp[i][j-1][1]+(a[j-1]!=a[j]));
        }
    }
    printf("%d
",min(dp[1][n][0],dp[1][n][1]));
}
View Code

滚动数组

#include<bits/stdc++.h>
using namespace std;
const int N=5001;
int n,f[N][N],bf[N],cnt,ans,pre[N][3],fore[N][3];

int main()
{
//    freopen("in.in","r",stdin);
//    freopen("2.out","w",stdout);
    scanf("%d",&n);
    cnt++;
    scanf("%d",&bf[cnt]);
    for(int i=2;i<=n;i++)
    {
        int tem;
        scanf("%d",&tem);
        if(tem!=bf[cnt])
        {
            cnt++;
            bf[cnt]=tem;
        }
    }
    
    for(int k=3;k<=cnt;k++)
    {
        for(int i=1;i<=cnt-k+1;i++)
        {
            f[i][k]=max(fore[i+k-2][(k-2)%3],max(pre[i+1][(k-2)%3],f[i][k]));
            if(bf[i]==bf[i+k-1])f[i][k]++;
            pre[i][k%3]=max(pre[i][(k-1)%3],f[i][k]);
            fore[i+k-1][k%3]=max(fore[i+k-1][(k-1)%3],f[i][k]);
        }
    }
    int ans=max(pre[1][cnt%3],fore[cnt][cnt%3]);
    ans=cnt-1-ans;
    printf("%d
",ans);
    return 0;
}
View Code

还有一种方法是:先把初始颜色序列去重,设去重后长度为n,然后找最长回文子序列len,答案就是n-ceil(len/2)。

因为对于一个回文子序列,只需操作floor(len/2)次,非回文序列长度为n必须两两合并共n-1次,因为起点可以任选,所以选最长回文子序列的中点作为起点,共操作n-ceil(len/2)次。


---------------------
原文:https://blog.csdn.net/Wen_Yongqi/article/details/86989782

原文地址:https://www.cnblogs.com/shuaihui520/p/10397956.html