【Jason's_ACM_解题报告】Color Length

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 character and the distance of two adjacent cars is assumed to be 1. Figure 1 shows an example of such cars on the road. For convenience, the numbers in Figure 1 represent the locations of each car.


Figure 1. Cars in different colors on the road


For any color c, location(c) represents set of the locations of the cars painted in color c and color length L(c) is defined as follows:

L(c) = max location(c) - min location(c)
For example, according to Figure 1, location(G) = {1, 5, 6}, location(Y ) = {2, 7}, location(B) = {3}, and location(R) = {4, 8}. Hence the color length of each color and the sum of the color lengths are as follows.

In Gyeongju City, almost all the roads including the main street of the city were constructed more than 500 years ago. The roads are so old that there are a lot of puddles after rain. Visitors have complained about the bad condition of the roads for many years. Due to the limited budget, the mayor of the city decided to repair firstly the main street of the city, which is a four-lane road, two lanes for each direction.

However, since the main street is a backbone of the city, it should not be blocked completely while it is under repair, or it is expected that serious traffic jams will occur on almost all the other roads in the city. To allow cars to use the main street during the repair period, the city decided to block only two lanes, one lane for each direction. Hence, the cars in the two lanes for each direction should merge into a single lane before the blocked zone.

For instance, as shown in Figure 2, cars in the two lanes merge into a single lane as shown in Figure 3. To differentiate the cars in the same color, a unique identifier is assigned to each car.

Figure 2. Cars moving in two lanes before merging


Figure 3 shows two different merging scenarios after merging the cars from the two lanes. As shown in Figure 3, cars in the two lanes do not necessarily merge one by one from each lane. The distance between two adjacent cars after merging is also assumed 1.

After merging (Scenario 1):


After merging (Scenario 2):


Figure 3. Two different merging scenarios

For each merging scenario shown in Figure 3, the color length for each color and the sum of the color lengths are as follows:

As you can imagine, there are many different ways of merging other than the two examples shown in Figure 3.

Given two character strings which represent the color information of the cars in the two lanes before merging, write a program to find the sum of color lengths obtained from the character string, which is the color information of cars after merging, such that the sum of color lengths is minimized.

Input
Your program is to read from standard input. The input consists of T test cases. The number of test cases T is given in the first line of the input. Each test case consists of two lines. In the first line, a character string of length n (1 ≤ n ≤ 5, 000) that is the color information of the cars in one lane before merging is given. In the second line, a character string of length m (1 ≤ m ≤ 5, 000) that is the color information of the cars in the other lane is given. Every color is represented as an uppercase letter in English, hence the number of colors is less than or equal to 26.


Output
Your program is to read from standard input. Print exactly one line for each test case. The line should contain the sum of color lengths after merging the cars in the two lanes optimally as described above. The following shows sample input and output for two test cases.


Sample Input
2
AAABBCY
ABBBCDEEY
GBBY
YRRGB


Sample Output
10
12

这是一道非常重要的题目,打破了我一贯的对动态规划解题的思维,让我更透彻的体会到了什么是最优子结构、什么是阶段

Liu的讲解虽然让我明白了如何去解决,但是究竟状态数组以及处理细节还是很模糊或者说是有歧义。

设d[i][j]表示当前已经拿走了第一个字符串的 i 个字符和第二个字符串的 j 个字符后对整个题目答案的贡献值。

这样状态转移方程即为d[i][j]=min(d[i-1][j]+cost[i-1][j],d[i][j-1]+cost[i][j-1])。

其中cost[i][j]的表示以及计算很值得思考:它把每个颜色的长度普遍化了,也就是说,我们其实不用关注当前没有出现的最后一个元素具体都是哪些,只需要知道一共有几个,这样每次加入一个元素进入最终的序列里时,直接加上他的数量即可,这个数量就是cost[i][j],并且每一次操作都需要对它的值进行维护。

其中需要注意的是滚动数组的使用!!

由于数据规模达到5000,而开一个二维数组就需要占用4×5000×5000字节的空间,将近100MB,对于本题来说这是无法承受的,最终将导致TLE或者是MLE。所以我们需要使用滚动数组,从而减少空间开销。



附代码如下:

AC代码:

#include<cstdio> 
#include<cstring>

#include<algorithm>

using namespace std;

#define MAXN (5000+5)
#define OO (0x7fffffff)
#define CLR(x,y) (memset(x,y,sizeof(x)))

char p[MAXN],q[MAXN];
int sp[26],ep[26],sq[26],eq[26];
int d[2][MAXN],c[2][MAXN];

int main(){
//freopen("in.txt","r",stdin);
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%s%s",p+1,q+1);
		
		int n=strlen(p+1);
		int m=strlen(q+1);
		for(int i=1;i<=n;i++)p[i]-='A';
		for(int i=1;i<=m;i++)q[i]-='A';
		
		for(int i=0;i<26;i++){sp[i]=sq[i]=OO;ep[i]=eq[i]=0;}
		
		for(int i=1;i<=n;i++){
			sp[p[i]]=min(sp[p[i]],i);
			ep[p[i]]=i;
		}
		
		for(int i=1;i<=m;i++){
			sq[q[i]]=min(sq[q[i]],i);
			eq[q[i]]=i;
		}
		
		CLR(d,0);CLR(c,0);
		int t=0;
		for(int i=0;i<=n;i++){
			for(int j=0;j<=m;j++){
				if(!i&&!j)continue;
				
				int tmp1=OO,tmp2=OO;
				if(i)tmp1=d[t^1][j]+c[t^1][j];
				if(j)tmp2=d[t][j-1]+c[t][j-1];
				d[t][j]=min(tmp1,tmp2);
				
				if(i){
					c[t][j]=c[t^1][j];
					if(sp[p[i]]==i&&sq[p[i]]>j)c[t][j]++;
					if(ep[p[i]]==i&&eq[p[i]]<=j)c[t][j]--;
				}else if(j){
					c[t][j]=c[t][j-1];
					if(sq[q[j]]==j&&sp[q[j]]>i)c[t][j]++;
					if(eq[q[j]]==j&&ep[q[j]]<=i)c[t][j]--;
				}
			}
			t^=1;
		}
		
		printf("%d\n",d[t^1][m]);
	}
//fclose(stdin);
	return 0;
}

TLE代码(算法正确):

#include<cstdio> 
#include<cstring>

#include<algorithm>

using namespace std;

#define MAXN (5000+5)
#define OO (0x7fffffff)
#define CLR(x,y) (memset(x,y,sizeof(x)))

char p[MAXN],q[MAXN];
int sp[26],ep[26],sq[26],eq[26];
int d[MAXN][MAXN],c[MAXN][MAXN];

int main(){
//freopen("in.txt","r",stdin);
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%s%s",p+1,q+1);
		
		int n=strlen(p+1);
		int m=strlen(q+1);
		for(int i=1;i<=n;i++)p[i]-='A';
		for(int i=1;i<=m;i++)q[i]-='A';
		
		for(int i=0;i<26;i++){sp[i]=sq[i]=OO;ep[i]=eq[i]=0;}
		
		for(int i=1;i<=n;i++){
			sp[p[i]]=min(sp[p[i]],i);
			ep[p[i]]=i;
		}
		
		for(int i=1;i<=m;i++){
			sq[q[i]]=min(sq[q[i]],i);
			eq[q[i]]=i;
		}
		
		CLR(d,0);CLR(c,0);
		for(int i=0;i<=n;i++){
			for(int j=0;j<=m;j++){
				if(!i&&!j)continue;
				
				int tmp1=OO,tmp2=OO;
				if(i)tmp1=d[i-1][j]+c[i-1][j];
				if(j)tmp2=d[i][j-1]+c[i][j-1];
				d[i][j]=min(tmp1,tmp2);
				
				if(i){
					c[i][j]=c[i-1][j];
					if(sp[p[i]]==i&&sq[p[i]]>j)c[i][j]++;
					if(ep[p[i]]==i&&eq[p[i]]<=j)c[i][j]--;
				}else if(j){
					c[i][j]=c[i][j-1];
					if(sq[q[j]]==j&&sp[q[j]]>i)c[i][j]++;
					if(eq[q[j]]==j&&ep[q[j]]<=i)c[i][j]--;
				}
			}
		}
		
		printf("%d\n",d[n][m]);
	}
//fclose(stdin);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值