BZOJ1260: [CQOI2007]涂色paint
1260: [CQOI2007]涂色paint
Time Limit: 30 Sec Memory Limit: 64 MBDescription
假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。 每次你可以把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。 用尽量少的涂色次数达到目标。
Input
输入仅一行,包含一个长度为n的字符串,即涂色目标。字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。
Output
仅一行,包含一个数,即最少的涂色次数。
Sample Input
Sample Output
【样例输入1】
AAAAA
【样例输入1】
RGBGR
【样例输出1】
1
【样例输出1】
3
AAAAA
【样例输入1】
RGBGR
【样例输出1】
1
【样例输出1】
3
HINT
40%的数据满足:1<=n<=10
100%的数据满足:1<=n<=50
from:
a799091501
经典的区间dp题
对于一个给定的结束状态,我们考虑他是怎么转移的:
显然 只能是由一个子区间再往左涂一次或者再往右涂一次
那么对于任意一个大于二的序列都可以分成两个子序列,所以这就是一道区间dp了!(鼓掌!
很容易发现 如果最s[l]==s[l+1]||s[r]==s[r-1] 那么就不需要多余的次数来涂他了(因为一次可以把这两个都涂上)
但是下一个可能就没有那么好理解了(我居然浪费了两个多小时,我真是太弱啦!
如果s[l]==s[r]
那么可以证明 涂了l(或者r)的时候,这一次涂色一定同时涂上了r 不然不可能是最优解(因为即使r不是另一个区间所需要的颜色,答案也不会变的更差)
也就是说,转移方程为dp[l][r]=min(dp[l+1][r-1]+1,min(dp[l+1][r],dp[l][r-1])) (s[l]==s[r])
因为取l和r,对另一个元素的贡献是等效的 所以只需要在他们中取min,并且这一次操作不会对答案产生改变
当然 另一种取法就是直接一笔从[l+1]画到[r-1] 这样答案++
以上属于特殊情况 对于其他的情况 只需要区间dp的经典递推式就可以了
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 using namespace std; 9 typedef long long ll; 10 typedef long double ld; 11 typedef pair<int,int> pr; 12 const double pi=acos(-1); 13 #define rep(i,a,n) for(int i=a;i<=n;i++) 14 #define per(i,n,a) for(int i=n;i>=a;i--) 15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 16 #define clr(a) memset(a,0,sizeof(a)) 17 #define pb push_back 18 #define mp make_pair 19 #define fi first 20 #define sc second 21 #define pq priority_queue 22 #define pqb priority_queue <int, vector<int>, less<int> > 23 #define pqs priority_queue <int, vector<int>, greater<int> > 24 #define vec vector 25 ld eps=1e-9; 26 ll pp=1000000007; 27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 32 ll read(){ ll ans=0; char last=' ',ch=getchar(); 33 while(ch<'0' || ch>'9')last=ch,ch=getchar(); 34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar(); 35 if(last=='-')ans=-ans; return ans; 36 } 37 const int N=100; 38 int f[N][N]; 39 char ch[N]; 40 int main(){ 41 scanf("%s",ch+1); int n=strlen(ch+1); 42 for (int p=1;p<=n;p++){ 43 for (int i=1;i<=n;i++){ 44 int j=i+p-1; 45 if (j>n) continue; 46 f[i][j]=j-i+1; 47 if (i!=j && ch[i]==ch[j]) f[i][j]=min(f[i][j],f[i+1][j]),f[i][j]=min(f[i][j],f[i+1][j]); 48 for (int k=i;k<j;k++){ 49 f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]); 50 } 51 } 52 } 53 printf("%d",f[1][n]); 54 return 0; 55 }