poj1934

题目大意:给出两个串求最长的公共子序列。最长公共子序列好求,难得是输出。

暴力dfs。n*n!跪了,主要是两个串如果大量的字符相同,dfs次数太多,TLE是必然的。

显然必须换姿势了。各位大牛给的是枚举26个字母。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ma   100
int data[ma][ma]={0};
char s1[ma]={},s2[ma]={};
int len1,len2;
int an; 
char s[ma]={};
int coun = 0;
struct node { char a[100];};
node answer[100009]={};
bool cmp(node a,node b)
{
if(strcmp(a.a,b.a))
return true;
return false;
}

void dfs(int i,int j,int sum)
{
printf("%d %d\n",i,j);
if(sum == an)
{
strcpy(answer[coun++].a,s);
return ;
}
if(i > 0 && j > 0 && data[i-1][j-1] > sum) // 两个串相同,这个剪枝无效!所以一直TLE
 return ;

for(int x = i; x < len1; x++)           // 如果两个串相同,不停的调用dfs. 相当于 n!数据打了,坑定会TLE的
 for(int y = j;y < len2; y++)
if(s1[x] == s2[y])
{  s[sum] = s1[x]; dfs(x+1,y+1,sum+1);}
return ;
}

int main()
{
scanf(" %s %s",s1+1,s2+1);
s1[0] =s2[0]= 'a'; len1 = strlen(s1);len2 = strlen(s2);
for(int i = 1; i < len1; i++)
 for(int j = 1; j < len2; j++)
if(s1[i] == s2[j])
 data[i][j] = data[i-1][j-1] + 1;
else
{
if(data[i-1][j] >= data[i][j-1])
 data[i][j] = data[i-1][j];
else
 data[i][j] = data[i][j-1];
}
an = data[len1-1][len2-1]; 
for(int i = 1; i < len1; i++)
  for(int j = 1; j < len2; j++)
if(s1[i] == s2[j] && data[i][j] == 1)
  dfs(i,j,0);
//sort(answer,answer+coun,cmp);
/*for(int i = 0; i < coun; i++)
 if(strcmp(answer[i].a,answer[i+1].a) != 0)
 printf("%s\n",answer[i].a);*/
return 0;
}

http://blog.csdn.net/tsaid/article/details/6726698这个的(我的语文不好复制过来的)。

1.用 pos1[ i ] [ j ] 代表字符 'a'+j 在 s1 中第 i 个字符前最后出现的位置 ( 即 1 -- i 这个范围内,最后出现的位置 )。
 若字符 'a' + j 不存在,那么pos1 [ i ] [ j ] = 0;
pos2 同理。
2.枚举最长公共子序列的每一个字符。假设最长公共子序列的长度为 cnt, s1 长度为 l1, s2 长度为 l2。 我们先确定第 cnt 个字符, dfs ( l1, l2, cnt )。
它可能是 a, b, c, ····,z  的其中之一。假设是 a, 那么需要找出 a 在 s1 及 a在 s2 中最后出现的位置 pos1 [ l1 ] [ 0 ], pos2 [ l2 ] [ 0 ],  令 p1 = pos1[l1][0], p2 = pos2[l2][0]。 若 dp[p1][p2] == cnt ,那么 ans [ cnt ] = a,
在此基础上枚举第 cnt - 1 个字符, dfs ( p1 - 1, p2 - 1, cnt - 1 )。·····最终找到第 1 个字符,结束。 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define N 90
char s1[N]={},s2[N]={};
int dp[N][N]={},pos1[N][30]={},pos2[N][30]={};


struct item
{ char str[N];}com;
bool operator > (const item &a,const item &b)
{
if(strcmp(a.str,b.str) > 0)
 return true;
return false;
}
priority_queue<item,vector<item>,greater<item> >qu;


void dfs(int l1,int l2,int c)
{
if(c < 1)
{ qu.push(com);return ;}if(l1 < 1 || l2 < 1)  return ;
for(int i = 0; i < 26; i++)                  //枚举26个字母,不会产生相同的序列。
{
int t1 = pos1[l1][i];
int t2 = pos2[l2][i];
if(dp[t1][t2] == c)       //优化。
{
com.str[c-1] = 'a' + i;
//printf("%s\n",com.str);
dfs(t1-1,t2-1,c-1);
}
}




}
int main()
{
int len1,len2;


scanf("%s%s",s1+1,s2+1);
len1 = strlen(s1+1);
len2 = strlen(s2+1);
for(int i = 1; i <= len1; i++)
 for(int j = 1; j <= len2; j++)
if(s1[i] == s2[j])
 dp[i][j] = dp[i-1][j-1]+1;
else
{
if(dp[i][j-1] > dp[i-1][j])
 dp[i][j] = dp[i][j-1];
else
 dp[i][j] = dp[i-1][j];
}


//printf("%d\n",dp[len1][len2]);
for(int i =1; i <= len1; i++)
 for(int j = 0; j < 26; j++)
if(s1[i] == 'a' + j)
 pos1[i][j] = i;
else
 pos1[i][j] = pos1[i-1][j];
for(int i = 1; i <= len2; i++)
 for(int j = 0; j < 26; j++)
if(s2[i] == 'a' + j)
 pos2[i][j] = i;
else
 pos2[i][j] = pos2[i-1][j];
com.str[dp[len1][len2]] = '\0';
dfs(len1,len2,dp[len1][len2]);
while(!qu.empty())
{
printf("%s\n",qu.top().str);
qu.pop();
}


return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值