【luogu】p1019 单词接龙

(碎碎念:初二的时候就开始写这道题,写了几天觉得啊好烦啊就不想写就放弃了,上初三之后终于抽出时间把这个题写完了
(搜索题要我狗命(缩成一团

题目链接:

https://www.luogu.com.cn/problem/P1019

题目描述

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at 和 atide 间不能相连。

输入格式

输入的第一行为一个单独的整数n (n≤20)表示单词数,以下n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.

输出格式

只需输出以此字母开头的最长的“龙”的长度

分析

由于题目中给出的数据范围单词数n<=20很小,可以用搜索dfs去解决

按照给出的字母,我们先确定好一个单词作为开头

枚举剩下的且使用没有超过两次的单词

对于每一个单词再枚举他的与前面单词相接位数并判断是否可行(要注意一个单词并不能完全包含在另一个单词中)。

如果他可以接在前一个单词上,

就先将它接入后增加的位数累加进最后的答案中,再去搜索下一个可以接上的单词。

边界状态:

当一个单词后无法再接入任何一个单词

我们就把答案与之前得到的最大答案进行比较取两者中最大值。

AC Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string> 
using namespace std;
int read(){
    int a = 0,f = 0;char p = getchar();
    while(!isdigit(p)){f|=p=='-';p = getchar();}
    while(isdigit(p)){a = (a<<3) + (a<<1) + (p^48);p = getchar();}
    return f?-a:a;
}
char c[25][100];//存单词
int ans;//记录每一种情况的答案
int flag[10000];//标记这个单词已经用过次数 
int Ans,n; //统计最终的答案 读入单词个数
bool Flag = 0;//判断一个单词后面是否还可以继续接入单词
void dfs(int x){//dfs!
    Flag = 0;
    for(int i = 1;i <= n;i ++){//尝试把i接在x的后面
        if(flag[i] == 2)continue;
        int leni = strlen(c[i]),lenx = strlen(c[x]);//记录两个单词长度 
        int cd = min(leni,lenx)-1;//最多能接在一起的长度为两个单词长度最小值-1
        int cd1,tot;
        int jl = 1;//记录我们想要接入几位
        while(jl <= cd){
            cd1 = jl,tot = 0;
            //int now = 0;
            while(cd1){//目前判断到的位置
                if(c[x][lenx-cd1] != c[i][jl-cd1])break;
                else tot++;
                cd1--;  
            }
            if(tot == jl)break;//两个可以接在一起
            jl++;
        }
        if(tot == jl && tot != 0){//记录下来并且去搜索下一个
            //cout<<x<<" "<<i<<" "<<tot<<endl;
            Flag = 1;
            ans += (leni-jl);
            flag[i] ++;
            dfs(i);
            ans -= (leni-jl);
            flag[i] --; 
        } 
    }
    if(Flag == 0){//后面什么也没法接的时候 
    
        Ans = max(ans,Ans);
    }
}
int main(){
    n = read();
    for(int i = 1;i <= n;i++)
        scanf("%s",&c[i]);
    
    char a;
    cin >> a;
    for(int i = 1;i <= n;i++){
        if(c[i][0] == a){
            //cout<<c[i]<<endl;
            flag[i]++;
            ans = strlen(c[i]);
            dfs(i);
        }
    }
    cout << Ans;
}

注意(不过可能也就我这么憨憨才会错的一个地方)

我们在枚举他可以接入的位数时,应该从小到大进行枚举,在能让两个单词相接的情况下,让相接的部分尽可能的小

比如:
abababab和abababc

如果我们从大到小枚举它可以接入的部分那么最后相接就会变为

ababababc 有9位

但我们从小到大枚举得到的才是最长的情况

ababababababc 有13位

好了好了没了没了别看了

猜你喜欢

转载自www.cnblogs.com/huixinxinw/p/12183210.html