区间dp [D

区间dp D - Flood Fill

题目大意:

如果[l,r] 这个连续的区间的数都相等,则说明这个是一个连通块,给你n个数,每一个数都代表这个位置的颜色,首先你要选取第一个操作的位置,之后你可以对这个位置所在的连通块进行改变颜色,可以改变成任意颜色。问最少多少次操作可以让这n个数变成一个颜色。

题解:

首先要重视这个操作的位置只有一个,就是最开始选取的。

使得 ([l,r]) 这个区间最后都是一样的颜色,那么只能从 ([l+1,r]) ([l,l]) 和 $[l,r-1] $ $ [r,r]$这两个状态转移过来。

我们可以假设第一个选取的位置在 ([l+1,r]) 或者 ([l,r-1]),那么 ([l,l]) 或者 ([r,r]) 则是要变成的颜色,那么最后([l,r]) 这个区间的颜色就是 ([l,l]) 或者 ([r,r])

如果是从 ([l+1,r]) 这个状态转移过来,那么最后这个颜色应该是和 (l) 这个位置的颜色是一样的。

如果是从 ([l,r-1]) 这个状态转移过来,那么最后这个颜色应该是和 (r) 这个位置的颜色是一样的。

所以需要第三维,对于区间 ([l,r]) 0表示从 (l) 转移过来,1表示从 (r) 转移过来。

#include <bits/stdc++.h>
#define id first
#define val second
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn=5e3+10;
int dp[maxn][maxn][2],a[maxn];

int main(){
    int n;
    scanf("%d",&n);
    memset(dp,inf,sizeof(dp));
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),dp[i][i][0]=dp[i][i][1]=0;
    for(int len = 2;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
            int j=i+len-1;
            dp[i][j][0]=min(dp[i+1][j][1]+(a[j]!=a[i]),dp[i+1][j][0]+(a[i+1]!=a[i]));
            dp[i][j][1]=min(dp[i][j-1][0]+(a[j]!=a[i]),dp[i][j-1][1]+(a[j-1]!=a[j]));
        }
    }
    printf("%d
",min(dp[1][n][0],dp[1][n][1]));
    return 0;
}
原文地址:https://www.cnblogs.com/EchoZQN/p/13255979.html