小明的喷漆计划(区间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;
}
posted @ 2021-03-13 17:36  Last-Order  阅读(111)  评论(0编辑  收藏  举报