HDU-2476-String painter

HDU-2476-String painter

传送门

这道题区间dp。
这道题目对我太不友好了。。。
维护答案的时候还是写了很久。。
啊啊啊。
这道题目给你两个序列。
你有一个画家助手。每次可以把连续的字符渲染成同一个字符。
问第一个序列A转化为B最少需要多少次。

我们这样考虑。dp[i][j]代表i~j字符转化的最少次数

我们先把一个空白的字符串转化成B最少需要多少次。
然后再来对比A和B。
维护答案。

初始化dp[i][j] = j - i + 1;//代表有多少个字符串就是最大操作次数
将空白字符转化为B的次数。
区间dp常用套路:
枚举长度j,i从后往前。
区间[i, j]内。枚举分界点。如果当前分界点的字符与i所指向的字符相等。
那么我们只需要改变i+1直到j即可。
dp[i][j] = min(dp[i][j], dp[i + 1][k] + dp[k + 1][j]);

之后维护ans[]
首先初始化一下ans[];
ans[i] = dp[0][i];
从第一个字符开始的值。index = 0;

之后开始比较
如果同一个索引位置上面的字符相等。
那么就代表这个地方的索引不需要被渲染。所以只需要渲染前面就可以了
ans[i] = ans[i - 1];
这个地方注意一下边界。如果i==0的话直接赋值为0就行,以免越界。特判一下
其余情况。
枚举0~i的范围即可。找到最佳切割点。
ans[i] = min(ans[i], ans[j] + dp[j + 1][i]);
当前ans[i]可能不是最佳的值。
有人可能会问了。在前面操作空白串处理dp的时候已经得到了最佳答案,为啥这里需要再维护一次。
是因为上面的if条件可能更改了ans[i],(对应于同一处的索引字符相等的情况,这种时不需要处理的),比如上面直接不处理ans[i] = 0的情况。所以最后需要再次维护(这里其实我卡了很久emmm,当时没想通。。。wa了好多次。。。)

代码部分:

#include <bits/stdc++.h>
#define mst(a, n) memset(a, n, sizeof(a))
using namespace std;
const int N  = 1e2 + 10;

string s1, s2;
int dp[N][N];
int ans[N];

int main()
{
	while (cin >> s1 >> s2)
	{
		int n = s1.size();
		mst(dp, 0);
		for (int j = 0; j < n; j++)
		{
			for (int i = j; i >= 0; i--)
			{
				dp[i][j] = dp[i + 1][j] + 1;
				for (int k = i + 1; k <= j; k++)
				{
					if (s2[i] == s2[k])
					{
						dp[i][j] = min(dp[i][j], dp[i + 1][k] + dp[k + 1][j]);
					}
				}
				
			}
		}
		for (int i = 0; i < n; i++)
		{
			ans[i] = dp[0][i];
		}
		for (int i = 0; i < n; i++)
		{
			if (s1[i] == s2[i])
			{
				ans[i] = !i ? 0 : ans[i - 1];
			}
			else
			{
				for (int j = 0; j < i; j++)
				{
					ans[i] = min(ans[i], ans[j] + dp[j + 1][i]);
				}
			}
		}
		cout << ans[n - 1] << endl;
	}
	return 0;
} 
发布了112 篇原创文章 · 获赞 3 · 访问量 2640

猜你喜欢

转载自blog.csdn.net/qq_44624316/article/details/104944572