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;
    }
    
  • 相关阅读:
    JAVA之数组
    Linux之判断字符串是否为空
    Python之操作HBASE数据库
    【转】Linux之crontab定时任务命令
    Python之shutil模块(复制移动文件)
    JAVA之列表集合ArrayList
    Python之多线程多进程
    前端之Javascript
    前端之DOM操作
    【转】写一个简单的爬虫来批量爬取新浪网的新闻
  • 原文地址:https://www.cnblogs.com/Ch-someone/p/9681232.html
Copyright © 2011-2022 走看看