练习13 P1127 词链

本文介绍了如何使用深度优先搜索(DFS)解决一个词链问题,规则是单词的头部出现次数等于尾部出现次数加一。通过计算每个单词的头部和尾部出现次数,以及使用数组记录可连接关系,找出首尾相连的单词链。若无法找到满足条件的首词,则按字典序输出第一个单词。
摘要由CSDN通过智能技术生成

P1127 词链

  • dog.gopher
  • gopher.rat
  • rat.tiger
  • aloha.aloha
  • arachnid.dog

根据本题给出的例子可知,'.' 两侧的字母一定相同, 但是第一个开头单词的字母可以是任意的,并且结尾的字母也可以是任意的,由样例提供的答案(题目要求字典序)

aloha.arachnid.dog.gopher.rat.tiger   可以看出 ' .' 两侧的字母出现的都是偶数个并且两两相对,但是a是特例,出现了3次,是尾部出现的次数 + 1

我们可以在任意举出一个例子 例如:

3
hell
low
wos  此时答案是  hell.low.wos

我们也可以发现 h 出现的次数 是1 个,也是尾部出现的次数 + 1

所以我们可以得到结论: 头部次数 = 它在尾部出现的次数 + 1,

那么它一定是第一个单词位置,那么我们再用 dfs 寻找 相互连接的单词 ,即可构成答案

但是有特殊情况, 就是第一个单词的头,和最后一个单词的尾,都是同样的单词,那么就都是偶数个 头/尾 了, 就没法用上面的办法找出现奇数次的单词构成第一个单词, 那么由于本题需要字典序, 所以我们不妨直接用  最小的单词,直接进行链接,因为 出现的单词头/尾, 都是 偶数,那么就可以直接去连接,如果匹配数量没有达到 n 个 ,那么就输出 *** ,即可

st 记录某单词在头部字母出现的次数    ed 记录某单词在尾部字母出现的次数

 st[s[i][0]]++;
 ed[s[i][s[i].size()-1]]++;

此时我们获取了单词出现的次数

se 判重,是否使用过

为了使dfs更快,我们提前将 某一个单词的尾部,可以对应那些个单词的头部的下标放入数组
即 if(i!=j&&s[i][s[i].size()-1]==s[j][0]) v[i].push_back(j);

然后遍历所有的单词,看一下哪一个单词的头部出现的次数 = 它尾部出现的次数 + 1;就证明它一定是开头的单词 然后调用  dfs(i,s[i]+'.',1);

因为v[i] 记录了它可以和谁连接,所以直接 auto i : v[x] 和里面获取的下标直接 连接即可

count==n 当连接数量达到 n ,证明成功,然后输出,退出程序

如果说没有找到 单词的头部出现的次数 = 它尾部出现的次数 + 1,那就证明出现了特殊情况,就可以按照 题目所说的,字典序,直接从 第一个排序好的单词,直接dfs

即dfs(1,s[1]+'.',1); 如果没有成功 输出 cout<<"***";

#include<bits/stdc++.h>
using namespace std;

const int N=1010;
vector<int> v[N];
string s[N];
int st[N],ed[N];
bool se[N];
int n;

void dfs(int x,string str,int count)
{
    if(count==n) 
    {
        str[str.size()-1]=' ';
        cout<<str;
        exit(0);
    }
    for(auto i : v[x])
    {
        if(!se[i])
        {
            se[i]=true;
            dfs(i,str+s[i]+'.',count+1);
            se[i]=false;
        }
    }
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        st[s[i][0]]++;
        ed[s[i][s[i].size()-1]]++;
    }
    
    sort(s+1,s+n+1);
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
     {
         if(i!=j&&s[i][s[i].size()-1]==s[j][0]) v[i].push_back(j);
     }
     
     for(int i=1;i<=n;i++)
     {
         if(st[s[i][0]] == ed[s[i][0]]+1) 
         {
             se[i]=true;
             dfs(i,s[i]+'.',1);
             se[i]=false;
         }
     }
     
     se[1]=true;
     dfs(1,s[1]+'.',1);
     se[1]=false;
     cout<<"***";
     return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值