topCoder Stripepainter


题:

给一个目标字符串,每次可以在空白字符串上将连续的位置刷成某个字符,问最少刷几次变成目标字符串。

如:AAA则是一次,ABA先刷成AAA再刷成ABA需要两次;RGBGRB 需要4次。

字符串长度最多50。

找的答案,两种。

第一种用递归,写起来比较简单,代码:


string s;
int dd[51][51][27];
int go(int i, int j, char c){//从i到j-1以c为底色
	while (i < j && s[i] == c)i++;//先找到和底色不同的字母
	while (i < j && s[j - 1] == c)j--;
	if (i == j)return 0;//如果没有则返回0
	if (i + 1 == j)return 1;//如果只有一个字母则返回1
	if (c == ' ' && (i > 0 || j < s.length()))return 100;
	if (dd[i][j][c - 'A'] >= 0)return dd[i][j][c - 'A'];
	int &r = dd[i][j][c - 'A'];
	r = 1000;
	for (int k = i + 1; k < j; k++){ int tmp = go(i, k, c) + go(k, j, c); r = r < tmp ? r:tmp; }//感受一下这个奇怪的符号。。不知道哪个版本的c++可以用,虽然理解
	for (int k = 'A'; k <= 'Z'; k++){ int tmp = 1 + go(i, j, k); r = r < tmp? r:tmp; }
	return r;
}
int minStrokes(string ss){
	memset(dd, 0xFFFFFFFF, sizeof(dd));
	s = ss;
	return go(0, s.length(), ' ');//返回空底色的最小笔画数
}




简单来说就是 go用来计算从i到j以c为底色需要的笔画数。定义好这个核心逻辑,并确定是正确的之后,两个循环就比较好理解。

假设go(i,j,c)在i,k和k,j(k>i&&k<j)的情况下返回的一定是正确的值,那么第一个循环一定可以得出在c为底色的情况下i到j的最小笔画,因为这是穷举。

第二个循环是说假如在c为底色的情况下(+1的作用),i到j以别的颜色为底色有更少的笔画数,那么返回这个更少的。

然后找到递归终结的三个条件:c为底色且i到j都是c;c为底色且i到j只有一个非底色的字母;c为底色且计算过i到j以c为底色的最少笔画数。有点类似数学归纳法的前两句。



第二种方法是非递归,思路略有不同,是把字符串分成前后两段穷举,原文:

http://blog.sina.com.cn/s/blog_57092d4b01000c8v.html

改成c++的代码:

int d[50][50][26] = { 1 };
int minPaint(string s){
	int i, j, k, l, n = s.length(), tmp;
	for (i = 0; i < n; i++) for (k = 0; k < 26; k++) if (s[i]-'A' == k)d[i][i][k] = 1; else d[i][i][k] = 2;
	//for (i = 0; i < 50; i++)for (k = 0; k < 26; k++) d[i][i][k] = 1;
	int ti, tj, tk;
	//把s分成两部分,j到j+l和j+l+1到j+i
	for (i = 1; i < n; i++)
	{
		for (j = 0; j + i < n; j++)
		{
			for (k = 0; k < 26; k++)
			{//从j到j+i的k
				d[j][j + i][k] = 100;
				//要找0-25中最小的值
				for (tk = 0; tk < 26; tk++)
				{
					for (l = 0; j + l < j+i; l++)
					{
						tmp = d[j ][j + l][k] + d[j + l + 1][j+i][tk];
						if (tk == k)tmp--;//底色相同则减一
						d[j][j + i][k] = d[j][j + i][k] < tmp ? d[j][j + i][k] : tmp;
					}

				}
			}
		}
	}

	int res = 100;
	for (i = 0; i < 26; i++)
	{
		res = res < d[0][n - 1][i] ? res : d[0][n - 1][i];
	}
	return res;
}

int mp(string s){
	stringbuf sb;
	int i = 0;
	while (i < s.size())
	{
		while (i+1 < s.size() && s[i] == s[i + 1])i++;
		sb.sputc(s[i++]);
	}
	return minPaint(sb.str());
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值