poj 2138 字符串dp

题意:给定一个起始单词,该单词长度为3,再给定一个字典。求从起始单词开始,每步在单词上添加一个字母并且仍然出现在字典中,这样能够达到的最长的那个单词(解保证这样的单词唯一)

思路:先将词典按照单词的长度排序。思路就是对于每个单词s,扫描比它长度小1的并且可以由初始单词到达的那些单词t,如果发现s可以由t添加一个字符组成,那么s能够由初始字符到达。

判断s是否能够由t构成一开始用的lcs,后来发现用O(串长)的方法即可。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
#define INF 0x3fffffff
#define clr(s,t) memset(s,t,sizeof(s))
#define N 1005
struct node{
    char s[83];
    int len,flag;
}p[N];
int dp[83][83];
char t[83];
int n;
int cmp(node a,node b){
    return a.len < b.len;
}
int lcs(int a,int b){
    int i,j;
    clr(dp, 0);
    for(i = 1;i<=p[a].len;i++)
        for(j = 1;j<=p[b].len;j++){
            if(p[a].s[i-1] == p[b].s[j-1])
                dp[i][j] = dp[i-1][j-1]+1;
            else
                dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
        }
    return dp[i-1][j-1];
}
int main(){
    int i,j,k,flag,a,b;
    char res[83];
    scanf("%d %s",&n,t);
    strcpy(res, t);
    for(i = 0;i<n;i++){
        scanf("%s",p[i].s);
        p[i].flag = 0;
        p[i].len = (int)strlen(p[i].s);
        if(!strcmp(t, p[i].s))
            p[i].flag = 1;
    }
    sort(p,p+n,cmp);
    for(i = 0;;i++)
        if(p[i].len == 4)
            break;
    a = 0;
    b = i-1;
    while(i<n){
        for(j = i,flag = 0;j<n&&p[j].len==p[i].len;j++)
            for(k = a;k<=b;k++)
                if(p[k].flag == 1 && lcs(j,k)==p[j].len-1){
                    p[j].flag = 1;
                    strcpy(res, p[j].s);
                    flag = 1;
                    break;
                }
        if(!flag)
            break;
        a = i;
        b = j-1;
        i = j;
    }
    printf("%s\n",res);
    return 0;
}


判断用更简单直接的方法,而非lcs:


int lcs(int a,int b){//a是否能够通过增加一个字符构成字符串b
    int i,j;
    for(i = j = 0;j<p[b].len && i<p[a].len;i++,j++)
        if(p[a].s[i] != p[b].s[j])
            i--;
    return i==p[a].len && (j==p[b].len||j==p[a].len);
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值