题:
给一个目标字符串,每次可以在空白字符串上将连续的位置刷成某个字符,问最少刷几次变成目标字符串。
如: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());
}