UVa 1625

DP状态设计的思路是不难想到的,问题在于维护,每一个状态的计算,除了计算最小的和,我们同时也要记录颜色的使用情况。同时我们对于最小和的更新也必须匹配新的方法:

  • 遍历颜色表,此前x颜色已经出现,那么此后,计算最小和,这个颜色就会贡献1个长度。
  • 若是此前y颜色已经饱和了,也就是说明这个颜色的“线段”已经确定,那么他的L(c)便不会再增长。
  • 每次状态转移都是从两个队列中取头元素的颜色,记得要将当前颜色状态表关于此颜色更新(相当于转移前状态对应颜色+1)

代码实现的时候,记录颜色的状态用了滚动数组,因为码力弱,所以编出来思考时间有点久,而且一个错误贡献了一个WA,数组开大点其实没有影响,代码实现思路更简洁,不过滚动数组空间优化还是可以的,O(nm)降到了O(n+m)。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
#include <vector>
using namespace std;

const int maxl= 5005;

char s1[maxl], s2[maxl];
int c[27];
int dp[maxl][maxl];
// count color and auxiliary count
int cc[maxl][27], ac[maxl][27];

void Init(int m, int n)
{
	int ix;
	memset(c, 0, sizeof(c));
	memset(cc, 0, sizeof(cc));
	memset(ac, 0, sizeof(ac));
	dp[0][0]= 0;

	for (int i= 1; i<= m; ++i){
		ix= s1[i]-'A';
		++c[ix];
	}
	for (int j= 1; j<= n; ++j){
		ix= s2[j]-'A';
		++c[ix];
	}

	for (int i= 1; i<= m; ++i){
		ix= s1[i]-'A';
		dp[i][0]= dp[i-1][0];

		for (int k= 0; k< 26; ++k){
			cc[i][k]= cc[i-1][k];
			if (cc[i-1][k] && (cc[i-1][k]< c[k])){
				++dp[i][0];
			}
		}
		++cc[i][ix];
	}
	for (int j= 1; j<= n; ++j){
		ix= s2[j]-'A';
		dp[0][j]= dp[0][j-1];

		for (int k= 0; k< 26; ++k){
			ac[j][k]= ac[j-1][k];
			if (ac[j-1][k] && (ac[j-1][k]< c[k])){
				++dp[0][j];
			}
		}
		++ac[j][ix];
	}
}

int main()
{
	int T, m, n;
	int ix, x;
	scanf("%d", &T);

	while (T--){
		scanf(" %s", s1+1);
		scanf(" %s", s2+1);
		m= strlen(s1+1);
		n= strlen(s2+1);

		Init(m, n);
		for (int j= 1; j<= n; ++j){
			for (int k= 0; k< 26; ++k){
				cc[0][k]= ac[j][k];
			}
			for (int i= 1; i<= m; ++i){
				ix= s2[j]-'A';
				dp[i][j]= dp[i][j-1];
				for (int k= 0; k< 26; ++k){
					if (cc[i][k] && (cc[i][k]< c[k])){
						++dp[i][j];
					}
				}

				x= dp[i-1][j];
				for (int k= 0; k< 26; ++k){
					if (cc[i-1][k] && (cc[i-1][k]< c[k])){
						++x;
					}
				}
				if (x< dp[i][j]){
					dp[i][j]= x;
					ix= s1[i]-'A';
					for (int k= 0; k< 26; ++k){
						cc[i][k]= cc[i-1][k];
					}
				}
				++cc[i][ix];
			}
		}
		cout<<dp[m][n]<<endl;
	}

	return 0;
}
原文地址:https://www.cnblogs.com/Idi0t-N3/p/13812762.html