小明的喷漆计划(区间DP) 题解
原题链接:LUOGU
题目描述
小明极其喜欢涂鸦,总是在墙上涂上各种颜色的漆。
现在小明得到一个任务,需要喷涂一段空白围墙,且单位长度内的颜色都是相同的。小明有一种喷涂工具,它可以给任意长度的一段墙面涂上任意颜色的漆,这样的操作计为一次操作。小明要完成这个任务,又想使得操作次数尽量少,就请你帮他解决这个问题吧。
输入
有多组输入数据。
每组包含一个长度不超过100的字符串(均由小写字母组成),代表需要涂鸦的墙面目标状态。
输出
至少需要几次操作,可达到目标。
样例输入
aaaaaa
fedcbaabcdef
aaabbbbb
aaabbbaaa
样例输出
1
6
2
2
题解
还是区间dp。
从最小的开始,假设只有\(1\)个a
,需要1次。
假设有\(2\)个,则有两种情况:
1.为aa
,显然为\(1\)次。
2.为ab
,显然为\(2\)次。
可以得到规律:
如果\(a[l] == a[r]\),则 \(dp[l][r] = min(dp[l][r] , dp[l][k] + dp[k+1][r] - 1)\),其中\(k\)为区间dp的断点。
如果\(a[l] != a[r]\),则 \(dp[l][r] = min(dp[l][r] , dp[l][k] + dp[k+1][r])\),其中\(k\)为区间dp的断点。
以上可以简化为:直接计算\(dp[l][r] = min(dp[l][r] , dp[l][k] + dp[k+1][r])\),后判断如果相等则--
。
可以写dfs或者递推。本人喜欢递推所以有以下代码:
代码
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f , N = 1e2+5;
char a[N];int dp[N][N],n;
signed main(){
while(scanf("%s",a + 1) != EOF){
n = strlen(a + 1);
memset(dp,0x3f,sizeof(dp));
for(int len = 1 ; len <= n ; len ++)
for(int l = 1 ; l + len - 1 <= n ; l ++){
int r = l + len - 1 ;
if(l == r)dp[l][r] = 1;
else{
for(int k = l ; k < r ; k ++)
dp[l][r] = min(dp[l][r] , dp[l][k] + dp[k+1][r]);
if(a[l] == a[r])dp[l][r] --;
}
}
printf("%d\n",dp[1][n]);
break;
}
return 0;
}