涂色
Description
假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。 每次你可以把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。 用尽量少的涂色次数达到目标。
Input
输入仅一行,包含一个长度为n的字符串,即涂色目标。字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。
Output
仅一行,包含一个数,即最少的涂色次数。
【样例输入1】
AAAAA
【样例输入1】
RGBGR
【样例输出2】
1
【样例输出2】
3
AAAAA
【样例输入1】
RGBGR
【样例输出2】
1
【样例输出2】
3
题解
此题含有一个原则:要使某一段涂的次数最少,一定先涂两端的颜色,那么即可列出dp方程:
f[i][j]表示i到j变为目标串的最小次数
f[i][j]=min(f[i+1][j],f[i][j-1]) (s[i]==s[j]);
f[i][j]=min(f[i][k]+f[k+1][j]) (s[i]!=s[j]);
f[i][j]=min(f[i][k]+f[k+1][j]) (s[i]!=s[j]);
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define inf 1000000000
using namespace std;
int f[55][55];
int main(){
string s;
cin>>s;
int n,m,i,j,k,len;
len=s.length();
s=" "+s;
for(i=0;i<=len;i++)f[i][i]=1;
for(i=len;i>=1;i--){
for(j=i+1;j<=len;j++){
if(s[i]==s[j])f[i][j]=min(f[i+1][j],f[i][j-1]);
else{
f[i][j]=inf;
for(k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
}
cout<<f[1][len];
}
/*
f[i][j]=min(f[i+1][j],f[i][j-1]) (s[i]==s[j]);
f[i][j]=min(f[i][k]+f[k+1][j]) (s[i]!=s[j]);
*/
String painter
Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2992 Accepted Submission(s): 1374
Problem Description
There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string painter. With the help of the painter, you can change a segment of characters of a string to any other character you want. That is, after using the painter, the segment is made up of only one kind of character. Now your task is to change A to B using string painter. What’s the minimum number of operations?
Input
Input contains multiple cases. Each case consists of two lines:
The first line contains string A.
The second line contains string B.
The length of both strings will not be greater than 100.
The first line contains string A.
The second line contains string B.
The length of both strings will not be greater than 100.
Output
A single line contains one integer representing the answer.
Sample Input
zzzzzfzzzzz abcdefedcba abababababab cdcdcdcdcdcd
Sample Output
6 7
Source
题解:
我们可以先按照上一道题的思路:先求出空字符串变为目标字符串的最小次数。然后在进行讨论。
初始串与目标串本来已经匹配的地方就无须再覆盖。
那么即可列出第二次dp方程:
dp[i]表示1到i初始串变为目标串的最小次数
dp[i]=dp[i-1] (s1[i]==s2[i])
dp[i]=min(dp[j]+f[j+1][i]) (s1[i]!=s2[i]) 其中f[i][j]表示空字符串变为目标串的最小次数
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define inf 1000000000
using namespace std;
int f[105][105];
int ans[105];
string s1,s2;
int main(){
while(cin>>s1>>s2){
memset(f,0,sizeof(f));
memset(ans,0,sizeof(ans));
int len,i,j,k;
len=s1.length();
s1=" "+s1;
s2=" "+s2;
for(i=0;i<=len;i++)f[i][i]=1;
for(i=len;i>=1;i--){
for(j=i+1;j<=len;j++){
if(s2[i]==s2[j])f[i][j]=min(f[i+1][j],f[i][j-1]);
else{
f[i][j]=inf;
for(k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
}
for(i=1;i<=len;i++){
ans[i]=inf;
if(s1[i]==s2[i])ans[i]=ans[i-1];
else{
for(j=0;j<i;j++)
ans[i]=min(ans[i],ans[j]+f[j+1][i]);
}
}
cout<<ans[len]<<endl;
}
}