zoukankan      html  css  js  c++  java
  • 涂色(CQOI2007)

    ——BZOJ1260_区间dp

    Description

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

    Input

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

    Output

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

    样例输入1

    AAAAA

    样例输入2

    RGBGR

    样例输出1

    1

    样例输出2

    3

    HINT

    40%的数据满足:1<=n<=10
    100%的数据满足:1<=n<=50

    Analysis

    这种题,一个序列,求最小次数,能看出来是区间dp吧。
    一般区间dp都是二维,我这里的i,j表示l,r,[i][j]表示(i,j)这个子序列。dp存答案。
    整个区间从什么状态转移过来?
    由短到长考虑,考虑长度为1的区间:dp[i][i]都是1,因为一个格子只用涂一次。
    考虑长度为2的区间:dp[i][i+1],如果i和i+1颜色相同,只用涂一次,若颜色不同,就涂两次。
    长度为3的区间,若1个格子与其他格子颜色不同,那就涂2次,全不同涂3次,全相同涂1次。
    ……
    继续推下去,我们会发现,长度为n的区间总是由它的的子区间转移过来,而且若这个区间的两端颜色相同,就会少涂一次色。
    找到这个规律之后,就能推出方程了。

    [dp[i][i+j] = min(dp[i][k],dp[k+1][i+j]) ]

    当区间两端颜色相同时

    [dp[i][i+j] = dp[i][i+j] - 1 ]

    代码

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int dp[5005][5005];
    char ss[5005];
    int n;
    int main()
    {
    	scanf("%s",ss+1);
    	n = strlen(ss+1);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			dp[i][j] = inf;
    	for(int i=1;i<=n;i++)
    		dp[i][i] = 1;
    	for(int j=1;j<=n;j++)
    	{
    		for(int i=1;i<=n;i++)
    		{
    			for(int k=i;k<=i+j-1;k++)
    			{
    				dp[i][i+j] = min(dp[i][i+j] , dp[i][k] + dp[k+1][i+j]);
    			}
    			if(ss[i] == ss[i+j])
    				dp[i][i+j]--;
    		}
    	}
    	printf("%d",dp[1][n]);
    	return 0;
    }
    
  • 相关阅读:
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    软件工程实践总结
  • 原文地址:https://www.cnblogs.com/Ch-someone/p/9681232.html
Copyright © 2011-2022 走看看