题目
题意;
将两个序列合并成一个序列是颜色跨度最短
思路:
因为和归并排序类似,开始想的是一个多阶段决策问题,
dp
用d(i,j)表示第一个序列长度i,第二个序列长度j的最短颜色跨度,对每一个状态有两种决策,i+1或者j+1.但是状态转移方程写不出,如果要知道一个元素的跨度就要知道开始和结束的下标.
紫书: 序列长度加一时,所有开始了但是还没有结束的颜色跨度都应该加一.
用rec[i][j]记录开始未结束的颜色个数
总共只出现一次的颜色不要算进去
d(i,j)=min[d(i-1,j)+rec[i-1][j] ,d(i,j-1)+rec[i][j-1] ];
最后提交tle ,百度发现是因为memset,注释掉,直接覆盖ac.
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <math.h>
#include<vector>
#include<time.h>
using namespace std;
char str1[5001];
char str2[5001];
int rec[5001][5001];
int d[5001][5001];
int main(){
//freopen("D:\\in.txt","r",stdin);
//freopen("D:\\out.txt","w",stdout);
int T;cin>>T;
getchar();
for(int k=0;k<T;k++){
/*memset(str1,0,sizeof(str1));
memset(str2,0,sizeof(str2));
memset(rec,0,sizeof(rec));
memset(d,0,sizeof(d));*/
gets(str1);
gets(str2);
int len1=strlen(str1);
int len2=strlen(str2);
int rec_cha[200];
memset(rec_cha,0,sizeof(rec_cha));
for(int i=0;i<len1;i++)
rec_cha[str1[i]]++;
for(int i=0;i<len2;i++)
rec_cha[str2[i]]++;
//rec[i][j];
int cnt=0;
for(int i=0;i<200;i++)
if(rec_cha[i]>1) cnt++;
for(int i=0;i<=len1;i++)
for(int j=0;j<=len2;j++){
int cpy[200];
//memcpy(cpy,rec_cha,sizeof(rec_cha));
memset(cpy,0,sizeof(cpy));
//int cnt1=cnt;
int cnt1=0;
for(int k=1;k<=i;k++)
cpy[str1[k-1]]++;
//if(rec_cha[str1[k-1]]>cpy[str1[k-1]]) cnt1++;
for(int k=1;k<=j;k++)
cpy[str2[k-1]]++;
for(int k=0;k<200;k++)
if(cpy[k]&&rec_cha[k]>cpy[k]) cnt1++;
rec[i][j]=cnt1;
}
//d[i][j]
d[0][0]=0;
for(int i=0;i<=len1;i++)
for(int j=0;j<=len2;j++)
if(!i&&!j) continue;
else if(!i) d[i][j]=d[i][j-1]+rec[i][j-1];
else if(!j) d[i][j]=d[i-1][j]+rec[i-1][j];
else d[i][j]=min(d[i][j-1]+rec[i][j-1],d[i-1][j]+rec[i-1][j]);
cout<<d[len1][len2]<<endl;
}
return 0;
}