标签:zoj
题意:
字符c1和c2的距离为d(c1, c2),已知两个字符串s和t,现在要找长度相等的两个字符串a和b,使得s是a的子序列,t是b的子序列,且a和b的距离最小。
思路:
字串和子序列是不一样的。。。。子序列是允许中间 间断 的,而字串必须是连续的...比赛的时候居然理解错了....T_T
这样的话,用最长公共子序列的思路来解决这道题就好啦~
dp[i][j]表示 “第一个串处理到第i个字符,第二个串处理到第j个字符” 时,最短的距离是什么。。
然后这种两个串的题目见的很多啦....很好转移啊!详见代码
后面用一些值 需要预处理一下然后保存下来~、、
路径输出使题目变得麻烦了一些啊..再根据刚才DP求得的最优值dfs回去 然后记录结果就好啦~
code:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
//-----------------------------------
const int maxn = 2005;
int z[maxn], lz;
int s[maxn], ls, t[maxn], lt;
int dist[maxn][maxn], va[maxn], vb[maxn];
int f[maxn][maxn];
int ansa[maxn*2], ansb[maxn*2], ca[maxn], cb[maxn], cnt;
void change(char *ss, int *tmp){
int len = strlen(ss);
for(int i = 0; i < len; i++){
tmp[i+1] = ss[i];
}
}
void init(){
char tmp[maxn];
scanf("%s", tmp);
lz = strlen(tmp);
change(tmp, z);
scanf("%s", tmp);
ls = strlen(tmp);
change(tmp, s);
scanf("%s", tmp);
lt = strlen(tmp);
change(tmp, t);
int u, v;
for(int i = 1; i <= lz; i ++){
u = z[i];
for(int j = 1; j <= lz; j++){
v = z[j];
scanf("%d",&dist[u][v]);
}
}
memset(va, INF, sizeof(va));
memset(vb, INF, sizeof(vb));
for(int i = 1; i <= lz; i++){
for(int j = 1; j <= lz; j++){
u = z[i], v = z[j];
if(va[u] > dist[u][v]){
va[u] = dist[u][v];
ca[u] = v;
}
if(vb[u] > dist[v][u]){
vb[u] = dist[v][u];
cb[u] = v;
}
// va[u] = min(va[u], dist[u][v]);
// vb[u] = min(vb[u], dist[v][u]);
}
}
}
int DP(int i, int j){
if(f[i][j] != INF) return f[i][j];
if(i == 0 && j == 0) return f[i][j] = 0;
if(i > 0) f[i][j] = min(f[i][j], DP(i-1, j) + va[s[i]]);
if(j > 0) f[i][j] = min(f[i][j], DP(i, j-1) + vb[t[j]]);
if(i > 0 && j > 0) f[i][j] = min(f[i][j], DP(i-1, j-1) + dist[s[i]][t[j]]);
return f[i][j];
}
void dfs(int i, int j){
int ans = f[i][j];
if(i > 0 && j > 0 && ans == f[i-1][j-1] + dist[s[i]][t[j]]){
ansa[cnt] = s[i];
ansb[cnt] = t[j];
cnt++;
dfs(i-1, j-1);
return;
}
if(i > 0 && ans == f[i-1][j] + va[s[i]]){
ansa[cnt] = s[i];
ansb[cnt] = ca[s[i]];
cnt++;
dfs(i-1, j);
return;
}
if(j > 0 && ans == f[i][j-1] + vb[t[j]]){
ansa[cnt] = cb[t[j]];
ansb[cnt] = t[j];
cnt++;
dfs(i, j-1);
return ;
}
}
void solve(){
memset(f, INF, sizeof(f));
int ans = DP(ls, lt);
printf("%d\n",ans);
cnt = 0;
dfs(ls, lt);
for(int i = cnt-1; i >= 0; i--){
printf("%c",ansa[i]);
}
printf("\n");
for(int i = cnt-1; i >= 0; i--){
printf("%c",ansb[i]);
}
printf("\n");
}
int main(){
init();
solve();
return 0;
}
然后这种两行的题目真的是见了许多了....然而并不怎么会....昨晚题目一定要注意多想想啦。。。
比赛的时候队友读错题真的是没办法....自己拿到题目要先确认一下呀..T_T。。。sigh...
版权声明:本文为博主原创文章,未经博主允许不得转载。
ZOJ 2366 Weird Dissimilarity (简单DP)
标签:zoj
原文地址:http://blog.csdn.net/u013382399/article/details/46861153