• 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;
    }
    
  • 相关阅读:
    SlipHover,能感知鼠标方向的图片遮罩效果jQuery插件
    jQuery插件开发精品教程,让你的jQuery提升一个台阶
    HTML5打造的炫酷本地音乐播放器-喵喵Player
    无论何时,记得做好代码的清理工作
    statcounter统计的浏览器市场占有率
    开大你的音响,感受HTML5 Audio API带来的视听盛宴
    requestAnimationFrame,Web中写动画的另一种选择
    好的用户界面-界面设计的一些技巧
    Windows上帝模式,上帝应该就是这样使用Windows的
    JavaScript字符转Unicode,顺便说句:GitHub的Oh no页面很亮
  • 原文地址:https://www.cnblogs.com/zach20040914/p/12978948.html
Copyright © 2020-2023  润新知