UVa1625 Color Length

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

char p[maxn], q[maxn];   //保存p,q串
int sp[size], sq[size], ep[size], eq[size];  //记录p和q结束和开始的位置
int dp[2][maxn], c[2][maxn];     //c[i][j]记录当前有多少序列一开始但是未结束

int main(){
	int i, T,n,m,j,id;
	scanf("%d", &T);
	while (T--){
		scanf("%s%s", p + 1, q + 1);
		n = strlen(p + 1);
		m = strlen(q + 1);

		for (i = 1; i <= n; i++) p[i] -= 'A';
		for (j = 1; j <= m; j++)q[j] -= 'A';

		//计算p和q中开始序列和结束序列
		memset(sp, 0x3f, sizeof(sp));
		memset(sq, 0x3f, sizeof(sq));
		memset(ep, 0, sizeof(ep));
		memset(eq, 0, sizeof(eq));

		for (i = 1; i <= n; i++){
			sp[p[i]] = min(sp[p[i]], i);
			ep[p[i]] = i;
		}
		for (i = 1; i <= m; i++){
			sq[q[i]] = min(sq[q[i]], i);
			eq[q[i]] = i;
		}

		int t = 0;
		for (i = 0; i <= n; i++){
			for (j = 0; j <= m; j++){
				if (!i&&!j){ dp[i][j] = c[i][j] = 0; continue; }

				int v = INF, u = INF;
				if (i) v = dp[t ^ 1][j] + c[t ^ 1][j];
				if (j) u = dp[t][j - 1] + c[t][j - 1];

				//dp[i][j]=min(dp[i][j-1]+c[i][j-1],dp[i-1][j]+c[i-1][j]);
				if (v < u){
					dp[t][j] = v; c[t][j] = c[t ^ 1][j];
					id = p[i];
					//如果p[i]还没有出现过,并且在q[j]后面还有
					if (sp[id] == i&&sq[id]>j)c[t][j]++;
					//如果p[i]之前出现过,并且此次为最后一次出现
					if (ep[id] == i&&eq[id] <= j)c[t][j]--;
				}
				else{
					dp[t][j] = u; c[t][j] = c[t][j - 1];
					id = q[j];
					if (sq[id] == j&&sp[id] > i)c[t][j]++;
					if (eq[id] == j&&ep[id] <= i)c[t][j]--;
				}
			}
			t ^= 1;
		}
		printf("%d
", dp[t^1][m]);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/td15980891505/p/5791293.html