zoukankan      html  css  js  c++  java
  • POJ 1934 Trip【最长公共子序列输出】

    Description

    Alice and Bob want to go on holiday. Each of them has planned a route, which is a list of cities to be visited in a given order. A route may contain a city more than once. 
    As they want to travel together, they have to agree on a common route. None wants to change the order of the cities on his or her route or add other cities. Therefore they have no choice but to remove some cities from the route. Of course the common route should be as long as possible. 
    There are exactly 26 cities in the region. Therefore they are encoded on the lists as lower case letters from 'a' to 'z'.

    Input

    The input consists of two lines; the first line is Alice's list, the second line is Bob's list. 
    Each list consists of 1 to 80 lower case letters with no spaces inbetween.

    Output

    The output should contain all routes that meet the conditions described above, but no route should be listed more than once. Each route should be printed on a separate line. There is at least one such non-empty route, but never more than 1000 different ones. Output them in ascending order.

    Sample Input

    abcabcaa
    acbacba

    Sample Output

    ababa
    abaca
    abcba
    acaba
    acaca
    acbaa
    acbca

    思路:看到一大牛的博客这样写道:

    1)首先按照常规的方法求出最长公共子序列的长度
    也就是用O(MN)的那个动态规划,结果放在二维数组dp
    dp[i][j] = {
    字串a的1~i部分与字串b的1~j部分的最长公共子序列的长度 }
    2
    )求辅助数组
    last1[i][j] = {
    到下标i为止,字符j在字串a中最后一次出现的下标 }
    last2[i][j] = {
    到下标i为止,字符j在字串b中最后一次出现的下标 }
    3
    )枚举最长公共字串的每一个字符
    从最后一个字符开始枚举
    比如说现在枚举最后一个字符是'C'的情况。
    那么 'CDCD' 与 'FUCKC' 这两个字串。
    一共有 (0, 2) (0, 4) (2, 2) (2. 4) 这四种可能。
    很明显前三个是可以舍弃的,因为第四个优于前三个,为后续的枚举提供了更大的空间。
    last
    数组正好是用来做这个的。
    4
    )排序输出
    代码里用了stl的set
    注意,由于刚刚的枚举过程是针对每个字符,所以是不用判重的。
    代码如下:

    #include<stdio.h>
    #include<set> 
    #include<string.h>
    #include<iostream>
    #include<algorithm>
    #include<string> 
    using namespace std;
    int dp[105][105];
    char ch1[105], ch2[105], temp[105];
    int last1[105][27], last2[105][27]; 
    set<string>SET;
    void find(int x, int y, int len)
    {
    	int i, j; 
    	if(len<=0)
    	{
    		SET.insert(&temp[1]);
    		return ;
    	}
    	if(x>0&&y>0)
    	{
    		for(i=0; i<26; i++)
    		{
    			int t1=last1[x][i];
    			int t2=last2[y][i];
    			if(dp[t1][t2]==len)
    			{
    				temp[len]='a'+i;
    				find(t1-1, t2-1, len-1);
    			}
    		}
    	}
    }	 
    int main()
    {
    	int i, j, len1, len2;
    	while(scanf("%s %s", &ch1[1], &ch2[1])!=EOF)
    	{
    		memset(last1, 0, sizeof(last1));
    		memset(last2, 0, sizeof(last2));
    		memset(dp, 0, sizeof(dp));
    		len1=strlen(&ch1[1]);
    		len2=strlen(&ch2[1]);
    		for(i=1; i<=len1; i++)
    			for(j=1; j<=len2; j++)
    			{
    				if(ch1[i]==ch2[j])
    					dp[i][j]=dp[i-1][j-1]+1;
    				else
    					dp[i][j]=max(dp[i][j-1], dp[i-1][j]);
    			}
    		for(i=1; i<=len1; i++)
    			for(j=0; j<26; j++)
    			{
    				if(ch1[i]=='a'+j)
    					last1[i][j]=i;
    				else
    					last1[i][j]=last1[i-1][j];
    			}
    		for(i=1; i<=len2; i++)
    			for(j=0; j<26; j++)
    			{
    				if(ch2[i]=='a'+j)
    					last2[i][j]=i;
    				else
    					last2[i][j]=last2[i-1][j];
    			}
    		temp[dp[len1][len2]+1]='\0'; 
     	 	find(len1, len2, dp[len1][len2]);
    		set<string>::iterator it;
            for(it=SET.begin();it!=SET.end();it++)
            {
                printf("%s\n",(*it).c_str());
            }
    	}
    	return 0;
    }	   

     

  • 相关阅读:
    2016/3/16 高级查询 ①连接查询 ②联合查询 ③子查询 无关 相关
    2016/3/13 七种查询 (普通查询 条件查询 排序查询 模糊查询 统计查询 分组查询 分页查询 )
    2016/3/13 MySQL 增删查改 CRUD 用代码实现
    2016/3/10 数据库简单操作( 创建数据库 创建表 数值类型 主键 外键 自动递增 )
    2016/3/10 PHP环境搭建 LAMP WAMP
    2016/3/10 PHP (超文本预处理器) 是什么?
    2016/3/1 淘宝 腾讯 网易 css初始化代码 以及最基础的初始化
    判断i在字符串中出现的次数(2016.1.12P141-1)
    2016-1-9作业——输出二维数组的和
    2016-1-8作业
  • 原文地址:https://www.cnblogs.com/Hilda/p/2616862.html
Copyright © 2011-2022 走看看