BZOJ1260: [CQOI2007]涂色paint

1260: [CQOI2007]涂色paint

Time Limit: 30 Sec  Memory Limit: 64 MB

Description

假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。 每次你可以把一段连续的木版涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。 用尽量少的涂色次数达到目标。

Input

输入仅一行,包含一个长度为n的字符串,即涂色目标。字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。

Output

仅一行,包含一个数,即最少的涂色次数。

Sample Input

 

Sample Output

【样例输入1】
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 }
View Code

 

 

posted @ 2017-09-30 14:08  SXia  阅读(196)  评论(0编辑  收藏  举报