BZOJ 1260--涂色(区间DP)

1260: [CQOI2007]涂色paint

Time Limit: 30 Sec  Memory Limit: 64 MB
Submit: 1691  Solved: 1023
[Submit][Status][Discuss]

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

题目链接:

    http://www.lydsy.com/JudgeOnline/problem.php?id=1260

Solution

    常见的区间DP。。。

    f [ i ] [ j ] 表示从 i 到 j 至少要涂几遍。。。

    状态转移方程显然。。。。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 100
#define LL long long
using namespace std;
int n;
char s[N];
int f[N][N];
int main(){
	int u;
	scanf("%s",s+1);
	n=strlen(s+1);
	for(int i=1;i<=n;i++) f[i][i]=1;
	for(int l=2;l<=n;l++)
		for(int i=1;i<=n+1-l;i++){
			u=i+l-1;
			f[i][u]=N;
			if(s[i]==s[u]){
				f[i][u]=min(f[i][u-1],f[i+1][u]);
				if(u-1>=i+1) f[i][u]=min(f[i][u],f[i+1][u-1]+1);
			}
			else{
				for(int j=i;j<u;j++)
					f[i][u]=min(f[i][u],f[i][j]+f[j+1][u]);
			}
		}
	printf("%d\n",f[1][n]);
	return 0;
}

  

  

This passage is made by Iscream-2001.

时间: 2024-12-29 07:21:03

BZOJ 1260--涂色(区间DP)的相关文章

bzoj 1260涂色 题解

题面 区间dp, 我学的也不怎么好. myj说动态规划就是搜索的无限剪枝. 所以是搜了网上的代码, 看了看. 思路就是枚举区间,f数组就是存储从i到j需要的最少次数, 当然一开始他们的值要先设置一个很大的值, 单独的区间也就是他自己这个点赋初值为1, 表示涂好这个只需要一次. 如果这两个区间的边界是一样的颜色直接用i + 1到j和i到j - 1这两个位置更新, 如果这两个区间的边界的颜色并不一样, 那就分成两段枚举k, 然后合并区间. 动规的代码一般不会太冗杂(我理解的是这样), 仔细想想其实也

BZOJ 1260 涂色

区间dp. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 55 #define inf 2000000000 using namespace std; int n,dp[maxn][maxn]; char s[maxn]; int main() { scanf("%s",s);n=strlen(s); for (

BZOJ 1055 玩具取名(区间DP)

很显然的区间DP,定义dp[i][j][k], 如果dp[i][j][k]=1表示字符串[i,j]可以组成k字符. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map>

BZOJ 1090 字符串折叠(区间DP)

很明显的区间DP,设dp[l][r]表示[l,r]区间的字符串折叠后的最小长度. 可以通过两种方向转移,dp[l][r]=min(dp[l][i]+dp[i+1][r]). 另一种是折叠,dp[l][r]=min(dp[l][l+k-1]+cal((r-l+1)/k)+2).其中k是能整除(r-l+1)的数且区间能够折叠成k份,cal()函数计算数字的位数. 另外用了线段树维护hash值,可以每次验证logn. # include <cstdio> # include <cstring&

BZOJ 1068 [SCOI2007]压缩 区间DP

题意:链接 方法:区间DP 解析: MD写题解(吐槽)写到一半markdown挂了什么鬼! 要不要这样!你知道我的内心是什么样的吗! 吐槽,啊呸,写题解写到一半突然丢失了我的内心是崩溃的好吗! 来我们重新写题解(吐槽) 这道题我刚开始列了个瞎(和谐)动规(二维的裸区间) 加上乱七八糟的判断是否有M后,居然有交叉! 一定是我逻辑错误,对就是这样! 后来又是一顿瞎(和谐)搞之后,代码抽的爆炸,然后我一测,c-free挂掉- - 过了一个小时后,我选择死亡. 然后看了一眼hzw的题解. 看到那个三维之

bzoj 1003物流运输 区间dp+spfa

基本思路: 一开始确实没什么思路,因为觉得怎么着都会超时,然后看一下数据范围,呵,怎么都不会超时. 思路: 1.看到能改变线路,想到可以用以下区间dp,区间dp的话,先枚举长度,枚举开始位置,然后枚举中间点 dp[i][j]=min(dp[i][j],dp[i][z]+dp[z][j]+k); 2.然后每段时间最短路究竟是多少,然后因为不会超时,所以就二重循环枚举就好了 (ps:这里要说明一下给自己提个醒: spfa就是队列优化的迪杰斯特拉,然后的话vis数组每次出一个就置零一个,如果不置零是错

[BZOJ 1260][CQOI2007]染色(DP)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1260 分析: f[i][j]表示i~j刷成s[i]~s[j]这个样子需要的最小次数 则若s[i]==s[j]:f[i][j]=min(f[i+1][j],f[i][j-1],f[i+1][j-1]+1) 若s[i]!=s[j]:f[i][j]=min(f[i][k]+f[k+1][j])

bzoj 1761: [Baltic2009]beetle 区间dp

1761: [Baltic2009]beetle Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 255  Solved: 92[Submit][Status][Discuss] Description 在一条直线上有N个点,每个点M升水. 一个虫子在坐标轴0点上,它每个单位时间移动一格,每个点的水每单位时间消失1升. 问虫子最多可以喝到多少水,喝水的时间忽略不计 Input 第一行给出数字N,M 下面N行给出N个点的坐标Xi 0 ≤ n ≤ 300,

BZOJ 2298 problem a(区间DP)

题意:一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低.”问最少有几个人没有说真话(可能有相同的分数) 思路:考虑最多有多少人说真,那么答案就是n-max. ai个人分数比他高,bi个人分数比他低,说明[bi+1,n-ai]里面的人分数相同. 用map维护某个区间是否相同. 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring>