uva1625 Color Length 线性动态规划

// uva1625 Color Length
// 这是好久之前在紫书(page 276)上看到的题目了
// 题目的意思是,给你两个长度分别为n和m的颜色序列(n,m<=5000)
// 都是由大写字母组成,要求按照顺序合并成同一个序列,即每次
// 可以把一个序列开头的颜色放在新序列的尾部
// 比如两个序列:GGBY 和 YRRGB至少有两种合并结果:
// GBYBRYRGB 和 YRRGGBBYB 对于每一种颜色c,跨度L(c)是最大位置和
// 最小位置之差,
// 问题是: 找一种合并的方式使得L(c)的总和最小。
//
// 首先,要换一种思维,每种颜色分别记录最小位置和最大位置,这个是不会有错的
// 之后,我们不是每种颜色单独去统计每次出现这种颜色时,他的最开始的位置,然
// 后再去加上此时的长度,而是所有颜色一起统计在第一个串i的位置和在第二个串j
// 的位置未结束但是已经开始的颜色的总数,因为最后统计的总的sigema(L)的时候
// 这些位置都是要算进去的
// 则:状态d(i,j)表示第一个串剩下i和第二个串剩下j时所得到的sigma(L)的最小值
// 则状态转移为:d(i,j) = min(d(i+1,j),d(i,j+1))+res(i,j);
// d(i+1,j)表示从第一个串拿走一个
// d(i,j+1)表示从第二个串拿走一个
// res(i,j)表示当前第一个串i,第二个串j位置时未结束但是已经开始的颜色的总数
//
//
//
// 感悟:
// 这道题真的看了很久很久,想了很久很久,看着书上的记录开始和结束的位置
// 我还能懂,之后计数的环节我就不太懂了,书上的代码我也没有看懂
// 目前只会这种状态的定义,而且细节部分还要多多的考究,会把紫书上的状态
// 再仔细的研习的,也望各位能够给予指点,小子实在是感激不尽
// 哎,继续练吧。。。
//
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cfloat>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#define ceil(a,b) (((a)+(b)-1)/(b))
#define endl '\n'
#define gcd __gcd
#define highBit(x) (1ULL<<(63-__builtin_clzll(x)))
#define popCount __builtin_popcountll
typedef long long ll;
using namespace std;
const int MOD = 1000000007;
const long double PI = acos(-1.L);

template<class T> inline T lcm(const T& a, const T& b) { return a/gcd(a, b)*b; }
template<class T> inline T lowBit(const T& x) { return x&-x; }
template<class T> inline T maximize(T& a, const T& b) { return a=a<b?b:a; }
template<class T> inline T minimize(T& a, const T& b) { return a=a<b?a:b; }

const int maxn = 5010;
int d[maxn][maxn];
char p[maxn],q[maxn];
int len1,len2;
int start[27][2];
int end[27][2];
int res[maxn][maxn];
const int inf = 0x3f3f3f3f;

void print(){
	for (int i=0;i<len1;i++){
		for (int j=0;j<len2;j++)
			printf("%d ",d[i][j]);
		puts("");
	}
}
void init(){
	scanf("%s",p);
	scanf("%s",q);
	len1 = strlen(p);
	len2 = strlen(q);
	for (int i=0;i<=len1;i++)
		for (int j=0;j<=len2;j++)
			d[i][j] = inf;
	memset(start,0x3f,sizeof(start));
	memset(end,-1,sizeof(end));
	for (int i=0;i<len1;i++){
		p[i] -= 'A';
	}
	for (int i=0;i<len2;i++)
		q[i] -= 'A';
	for (int i=0;i<len1;i++){
		if (start[p[i]][0] == inf)
			start[p[i]][0] = i;
		end[p[i]][0] = i;
	}
	for (int i=0;i<len2;i++){
		if (start[q[i]][1] == inf)
			start[q[i]][1] = i;
		end[q[i]][1] = i;
	}
	for (int i=0;i<=len1;i++)
		for (int j=0;j<=len2;j++){
			int cnt = 0;
			for (int k=0;k<26;k++){
				if (start[k][0]==inf&&start[k][1]==inf)	continue;
				if (start[k][0]>i-1&&start[k][1]>j-1)	continue;
				if (end[k][0]<i&&end[k][1]<j)	continue;
				cnt++;
			}
			res[i][j] = cnt;
		}
}

void solve(){
	d[len1][len2]=0;
	//print();
	for (int i=len1-1;i>=0;i--)
		d[i][len2] = d[i+1][len2]+res[i][len2];
	for (int j=len2-1;j>=0;j--)
		d[len1][j] = d[len1][j+1]+res[len1][j];
	for (int i=len1-1;i>=0;i--)
		for (int j=len2-1;j>=0;j--)
			d[i][j] = min(d[i+1][j],d[i][j+1])+res[i][j];
	printf("%d\n",d[0][0]);
//	print();
}

int main() {
	int t;
	//freopen("G:\\Code\\1.txt","r",stdin);
	scanf("%d",&t);
	while(t--){
		init();
		solve();
	}
	return 0;
}

时间: 2024-12-14 20:57:20

uva1625 Color Length 线性动态规划的相关文章

UVa1625 Color Length

/*----UVa1625 Color Length --用dp[i][j]表示当前两个串分别移走到第i和第个元素j时所获得的目标函数最优值,首先计算出两个序列中的每个元素开始和 结束的位置,在计算dp[i][j]的同时,还需要记住当前有多少颜色已经开始但是没有结束,这样不必关心每一个元素的L(c), 在程序递进计算的同时,只需要每次累加已经开始还没结束的元素个数即可. */ #define _CRT_SECURE_NO_DEPRECATE #include<iostream> #includ

UVA1625 Color Length(附 刘汝佳代码)

这是刘汝佳<算法竞赛入门经典第二版>的一道例题,只看书上的解释并没有理解,随后结合着代码才理解了. 解题思路:用d[i][j]表示序列1移走i个元素和序列2移走j个元素的最小"代价", 这个代价指的是由那些已经移出的字母合并而来的序列中已经出现但尚未结束的字母对总距离和的贡献.比如说一个合并而来的序列中有两个那样的字母,第一个在这个序列中后面有3个字母,另一个字母后面有2个字母,那么此时的代价就是2+3,表示这两个字母在这种合并情况下至少能为总距离和贡献5,因为随着向该序列

UVA1625 / UVALive 5841 Color Length DP

简单DP,dp[i][j]表示从第一个序列里取出i个和从第j个序列里取出j个的组合的最小值,可以从两个方向转移过来,每次转移加上已经出现过的且还没有出现完的字母的个数. O(n?m)的复杂度. 1625 Color Length Cars painted in different colors are moving in a row on the road as shown in Figure 1. The color of each car is represented by a single

uva 1625 - Color Length(dp 里面 L C S 问题解决方式变形)

LCS属线性结构上的动态规划,应该是动规里面很简单的一种类型. 最长公共子序列问题,一旦明确了状态,找到状态转移方程还是很简单的.但是对于本题来说,难点之一就是会很难想到该如何定义状态. 作为一只菜鸟,兹认为此题很复杂. 首先我是想不到每一步都把没到终点的字母全加上1,以及这种效果与你去找开始和结束的效果是一样的. 甚至,若不是在做动规的专题,我根本想不到这样的题目,会用动规来解决. 再一个,我想不到状态可以这么来定义"设d[ i ][ j ]表示两个序列分别已经拿出去了 i 个和 j 个元素

POJ-1458 LCS(线性动态规划)

此题经典线性动态规划. 代码如下: #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int maxn=505; int d[maxn][maxn]; int main(void){ string a,b; while(cin>>a>>b

动态规划②——线性动态规划(背包)

二.线性动态规划 上次只能算一个热身,这次是真正的动态规划了.还是洛谷(http://www.luogu.org/problem/show?pid=1048):题目描述 Description辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值.我会给你一段时间,在这段时间里,你可以采到一些

动态规划(模型转换):uvaoj 1625 Color Length

[PDF Link]题目点这里 这道题一眼就是动态规划,然而貌似并不好做. 如果不转换模型,状态是难以处理的. 巧妙地转化:不直接求一种字母头尾距离,而是拆开放到状态中. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int maxn=5010; 6 char s1[maxn],s2[maxn]; 7 int B1[26],E1[

1625 - Color Length——[动态规划]

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4500 题目分析: 本题要将两条路上的车辆混合成一路,混合方法可以是:每次将一个颜色序列中的开头颜色放入新序列的尾部.可以定义状态d[i][j]为第一个序列移走了i辆车,第2个序列移走了j辆车时,新序列的颜色长度.如何进行状态转移呢? 假设第一个序列为A[n],第二个序列为B[m]

线性动态规划

准确来说,动态规划是一种思想,而不是一种算法.算导里将它归结为——高级程序设计技巧. 在线性结构上进行状态转移DP,统称线性DP. 线性DP最常见的有: 子集和问题,LIS问题,LCS问题. 拓展之后有:子段和问题,杂类问题. 1. 子集和问题和硬币计数问题 子集和问题的一个实例: 〈S,t〉.其中,S={ 1 x , 2 x ,…, n x }是一个正整数的集合,c是一个正整数.子集和问题判定是否存在S的一个子集S1,使得s1中的各元素之和等于c. 这其实就是0/1背包. 硬币计数问题的一个实