区间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;
}