zoukankan      html  css  js  c++  java
  • POJ1934 Trip

    题目:Trip

    网址:http://poj.org/problem?id=1934

    爱丽丝和鲍勃想去旅行。

    他们每个人制定了一条旅行路线,每条路线包含一个按给定顺序访问的城市列表,一个城市可能会多次出现在同一路线中。

    因为他们想要一起去旅行,所以必须在旅行路线上达成一致。

    他们两个都不想改变他们的路线上的城市顺序或者在路线上额外添加城市。

    因此,他们只能移除各自路线中的一些城市,使得旅行路线达成一致,并且尽可能的长。

    该地区共有26个城市,用小写字母’a’到’z’表示。

    输入格式

    输入包含两行,第一行是爱丽丝的路线城市列表,第二行是鲍勃的路线城市列表。

    每个列表由1到80个小写字母组成,其间没有空格。

    输出格式

    按升序顺序输出所有满足条件的路线列表。

    每个路线列表占一行。

    输入样例:
    abcabcaa
    acbacba
    
    输出样例:
    ababa
    abaca
    abcba
    acaba
    acaca
    acbaa
    acbca
    

    很棒的一道题。题的外套是一道裸的LCS,实际上是考察搜索优化与动归的内在联系。

    熟知结论:
    dp[i, j] = max{
    dp[i, j - 1], dp[i - 1, j], dp[i - 1, j - 1] + 1 | a[i] == b[j]
    }

    我们因此获得了整个dp数组的值。

    如何输出所有的解?如果使用普通的搜索(加搜索深度限制),很显然会TLE;即便加了可行性剪枝,仍改变不了超时的风险。

    我们须寻找一些更好的优化。不妨设f1[i, j]表示字符串a中前i个字符组中(不包含a[i]),字符为j且位置最靠近i的位置。f1[i, j] = max{i || a[i] == j, f1[i - 1, j]};f2同理。

    接着正常搜索即可。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const int maxn = 80 + 5;
    vector <char> p;
    int n, m;
    int dp[maxn][maxn];
    int f1[maxn][26], f2[maxn][26];
    char a[maxn], b[maxn];
    void solve(int x, int y, int dep)
    {
    	if(x > n || y > m || min(n - x + 1, m - y + 1) < dep) return;//剪枝(1) 
    	if(dep == 0)
    	{
    		for(int i = 0; i < p.size(); ++ i) printf("%c", p[i]);
    		printf("
    ");
    		return;
    	}
    	for(int i = 0; i < 26; ++ i)
    	{
    		p.push_back('a' + i);
    		int pi = f1[x][i], pj = f2[y][i];
    		if(dep == dp[pi][pj]) solve(f1[x][i], f2[y][i], dep - 1);//DP特有的性质 剪枝
    		p.pop_back();
    	}
    	return;
    }
    int main()
    {
    	memset(a, ' ', sizeof(a));
    	memset(b, ' ', sizeof(b));
    	scanf("%s %s", (a + 1), (b + 1));
    	n = strlen(a + 1), m = strlen(b + 1);
    	for(int i = n; i >= 1; -- i)
    	{
    		for(int j = m; j >= 1; -- j)
    		{
    			dp[i][j] = max(dp[i + 1][j], dp[i][j + 1]);
    			if(a[i] == b[j]) dp[i][j] = max(dp[i][j], dp[i + 1][j + 1] + 1);
    		}
    	}
    	for(int i = 0; i < 26; ++ i)
    	{
    		f1[n + 1][i] = n + 2;
    		f2[m + 1][i] = m + 2;
    	}
    	for(int i = n; i >= 0; -- i)
    	{
    		for(int j = 0; j < 26; ++ j) f1[i][j] = f1[i + 1][j];
    		for(int j = 0; j < 26; ++ j)
    		{
    			if(a[i + 1] == j + 'a')
    			{
    				f1[i][j] = i + 1;
    			}
    		}
    	}
    	for(int i = m; i >= 0; -- i)
    	{
    		for(int j = 0; j < 26; ++ j) f2[i][j] = f2[i + 1][j];
    		for(int j = 0; j < 26; ++ j)
    		{
    			if(b[i + 1] == j + 'a')
    			{
    				f2[i][j] = i + 1;
    			}
    		}
    	}
    	p.clear();
    	solve(0, 0, dp[1][1]);
    	return 0;
    }
    
  • 相关阅读:
    mysql 导入CSV数据 [转]
    Linux用户态程序计时方式详解[转]
    [转] Bash脚本:怎样一行行地读文件(最好和最坏的方法)
    第二次作业
    软件工程原理与方法 第一次作业
    2017-02-19,周日整理
    2017-02-12,周日整理
    cnblogs,第一次博客纪念。
    堆和栈的区别(转过无数次的文章)
    Flash Player版本相关问题
  • 原文地址:https://www.cnblogs.com/zach20040914/p/12978948.html
Copyright © 2011-2022 走看看