uva 531 Compromise(LCS)

737 篇文章 0 订阅
该博客主要介绍了UVA 531道题目的解题方法,该题目要求找到两组字符串的最长公共子序列。博主分享了采用动态规划的思路来解决,并通过记录路径的技巧来处理相等字符串的情况。
摘要由CSDN通过智能技术生成

题目连接:531 - Compromise


题目大意:给出两组字符串, 各含若干的字符串, 要求求两组字符串的最长公共子序列, 并输出最长的方案, 若有多种可能输出任意一种。


解题思路:普通的最长子序列问题, 和一般求解一样, 不过要记录路径, 我的做法是开两各数组记录移动方式, x[p][q], y[p][q]。当x[p][q] == p - 1 && y[p][q] == q - 1 的时候就是说明两个字符串相等。


#include <stdio.h>
#include <string.h>
const int N = 105;
const int M = 30;
int max(int a, int b) { return a > b ? a : b; }

int n, m, ans[N], dp[N][N], x[N][N], y[N][N];
char a[N][M], b[N][M];

void Init() {
    n = m = 0;
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    memset(x, -1, sizeof(x));
    memset(y, -1, sizeof(y));
    memset(dp, 0, sizeof(dp));
}

int read() {
    int flag = 0;
    while (1) {
	if (scanf("%s", a[n]) != 1) {
	    flag = 1;
	    break;
	}
	if (strcmp(a[n], "#") == 0) break;
	n++;
    }

    while (1) {
	if (scanf("%s", b[m]) != 1) {
	    flag = 1;
	    break;
	}
	if (strcmp(b[m], "#") == 0) break;
	m++;
    }
    return flag;
}

void solve() {
    memset(ans, -1, sizeof(ans));
    for (int i = 1; i <= n; i++) {
	for (int j = 1; j <= m; j++) {
	    if (strcmp(a[i - 1], b[j - 1]) == 0) {
		dp[i][j] = dp[i - 1][j - 1] + 1;
		x[i][j] = i - 1;
		y[i][j] = j - 1;
	    }
	    else {
		if (dp[i - 1][j] > dp[i][j - 1]) {
		    dp[i][j] = dp[i - 1][j];
		    x[i][j] = i - 1;
		    y[i][j] = j;
		}
		else {
		    dp[i][j] = dp[i][j - 1];
		    x[i][j] = i;
		    y[i][j] = j - 1;
		}
	    }
	}
    }

    int sum = dp[n][m] - 1, p = n, q = m;

    while (1) {
	if (x[p][q] == -1 || y[p][q] == -1) break;
	if (sum < 0)	break;
	if ((p == x[p][q] + 1) && (q == y[p][q] + 1)) {
	    ans[sum--] = x[p][q];
	}
	int t = p;
	p = x[t][q], q = y[t][q];
    }
}

int main() {
    while (1) {
	Init();
	if (read())	break;
	solve();

	if (dp[n][m]) {
	    for (int i = 0; i < dp[n][m] - 1; i++)
		printf("%s ", a[ans[i]]);	
	    printf("%s\n", a[ans[dp[n][m] - 1]]);
	}
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值