当前位置: 首页 > wzjs >正文

网站模板flash大数据精准营销获客

网站模板flash,大数据精准营销获客,佛山顺德疫情最新消息今天,网站改版被降权见:P1127 词链 - 洛谷 题目描述 如果单词 X 的末字母与单词 Y 的首字母相同,则 X 与 Y 可以相连成 X.Y。(注意:X、Y 之间是英文的句号 .)。例如,单词 dog 与单词 gopher,则 dog 与 gopher 可以…

见:P1127 词链 - 洛谷

题目描述

如果单词 X 的末字母与单词 Y 的首字母相同,则 X 与 Y 可以相连成 X.Y。(注意:X、Y 之间是英文的句号 .)。例如,单词 dog 与单词 gopher,则 dog 与 gopher 可以相连成 dog.gopher

另外还有一些例子:

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

连接成的词可以与其他单词相连,组成更长的词链,例如:

aloha.arachnid.dog.gopher.rat.tiger

注意到,. 两边的字母一定是相同的。

现在给你一些单词,请你找到字典序最小的词链,使得每个单词在词链中出现且仅出现一次。注意,相同的单词若出现了 k 次就需要输出 k 次。

输入格式

第一行是一个正整数 n(1≤n≤1000),代表单词数量。

接下来共有 n 行,每行是一个由 1 到 20 个小写字母组成的单词。

输出格式

只有一行,表示组成字典序最小的词链,若不存在则只输出三个星号 ***

输入输出样例

in:
6
aloha
arachnid
dog
gopher
rat
tigerout:
aloha.arachnid.dog.gopher.rat.tiger

说明/提示

  • 对于 40% 的数据,有 n≤10;
  • 对于 100% 的数据,有 n≤1000。

这道题好难啊╥﹏╥

整体思路

这个问题本质上是在有向图中寻找欧拉路径。每个字符串可以看作图中的一条边,边的起点是字符串的首字符,终点是字符串的尾字符。我们需要判断:

  1. 是否存在欧拉路径
  2. 如果存在,找出具体的路径

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
string a[maxn];
string ans[maxn];
string now[maxn];
int sum=0;
int len[maxn];
int book[maxn];
map<char,int> s1,s2;
int n;
int flag=0;
void dfs(int last,int step) {if(flag==1)return;if(step==n) {flag=1;for(int i=1; i<=sum; i++) {ans[i]=now[i];}return;}for(int i=1; i<=n; i++) {if(book[i]==1)continue;if(a[last][a[last].length()-1]==a[i][0]) {now[++sum]=a[i];book[i]=1;dfs(i,step+1);sum--;book[i]=0;}}
}
int main() {scanf("%d",&n);for(int i=1; i<=n; i++) {cin>>a[i];len[i]=a[i].length();s1[a[i][0]]++;s2[a[i][len[i]-1]]++;}int start=1;sort(a+1,a+1+n);char s,t;for(char c='a'; c<='z'; c++) {if(abs(s1[c]-s2[c])==1) {if(s1[c]-s2[c]==1)s=c;else if(s2[c]-s1[c]==1)t=c;}}int cnt=s2[t];for(int i=1; i<=n; i++) {if(a[i][0]==s && (a[i][len[i]-1]!=t || cnt!=1)) {start=i;break;}}book[start]=1;now[++sum]=a[start];dfs(start,1);if(flag==0) {printf("***\n");return 0;}for(int i=1; i<=n; i++) {if(i!=n)cout<<ans[i]<<".";elsecout<<ans[i];}return 0;
}

能理解吗?

不能的话来分析一下    

——————————————————————————————————-——————— 

代码详细解析

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

这两行代码包含了所有标准库头文件并使用标准命名空间,简化了后续代码的编写。

数据结构与全局变量

const int maxn=1e5+5;
string a[maxn];     // 存储输入的所有字符串
string ans[maxn];   // 存储最终的合法接龙序列
string now[maxn];   // 存储当前DFS搜索路径中的接龙序列
int sum=0;          // 当前路径中的字符串数量
int len[maxn];      // 每个字符串的长度
int book[maxn];     // 标记字符串是否已被使用(1表示已使用,0表示未使用)
map<char,int> s1,s2;// 统计每个字符作为字符串开头和结尾的次数
int n;              // 字符串数量
int flag=0;         // 标记是否已找到合法解(1表示找到,0表示未找到)

输入处理与预处理

int main() {scanf("%d",&n);  // 读取单词数量for(int i=1; i<=n; i++) {cin>>a[i];  // 读取每个单词len[i]=a[i].length();  // 记录单词长度s1[a[i][0]]++;  // 统计首字母出现次数s2[a[i][len[i]-1]]++;  // 统计尾字母出现次数}int start=1;  // 默认从第一个单词开始搜索sort(a+1,a+1+n);  // 对单词进行字典序排序,确保找到的解是字典序最小的

这里使用两个map来统计每个字符作为字符串开头和结尾的次数,

为后续判断欧拉路径做准备。

例如:

  • 如果输入字符串为 ["abc", "cde", "efg"]
  • s1为 {'a':1, 'c':1, 'e':1}
  • s2为 {'c':1, 'e':1, 'g':1}

欧拉路径判断

​sort(a+1,a+1+n);  // 先排序,确保字典序最小
char s,t;
for(char c='a';c<='z';c++)
{if(abs(s1[c]-s2[c])==1){if(s1[c]-s2[c]==1)s=c;  // 起点字符(出度比入度多1)elseif(s2[c]-s1[c]==1)t=c;  // 终点字符(入度比出度多1)}
}
int cnt=s2[t];

这部分代码判断是否存在欧拉路径:

  • 欧拉路径条件
    1. 有向图中,所有节点的入度等于出度,或者
    2. 存在一个节点的出度比入度多 1 (起点),一个节点的入度比出度多 1 (终点),其余节点的入度等于出度
  • s是起点字符,t是终点字符
  • cnt记录终点字符t作为结尾的次数

确定搜索起点

​int start=1;
for(int i=1;i<=n;i++)
{if(a[i][0]==s && (a[i][len[i]-1]!=t || cnt!=1)){start=i;break;}
}
book[start]=1;
now[++sum]=a[start];

这部分代码确定 DFS 的起始字符串:

  • 优先选择以s开头且不以t结尾的字符串作为起点
  • 如果所有以s开头的字符串都以t结尾,则选择其中任意一个
  • 标记该字符串为已使用,并加入当前路径

深度优先搜索(核心逻辑)

​void dfs(int last,int step)
{if(flag==1)  // 已找到解,直接返回return;if(step==n)  // 已找到n个字符串的合法序列{flag=1;for(int i=1;i<=sum;i++){ans[i]=now[i];  // 保存当前路径到结果数组}return;}for(int i=1;i<=n;i++){if(book[i]==1)  // 跳过已使用的字符串continue;if(a[last][a[last].length()-1]==a[i][0])  // 当前字符串的结尾等于下一个的开头{now[++sum]=a[i];  // 加入当前路径book[i]=1;        // 标记为已使用dfs(i,step+1);    // 递归搜索sum--;            // 回溯book[i]=0;        // 撤销标记}}
}

这是典型的回溯 DFS 算法:

  • 参数说明
    • last:当前路径中最后一个字符串的索引
    • step:当前路径的长度
  • 终止条件
    • 当路径长度达到 n 时,表示找到合法解
    • 将当前路径保存到ans数组中,并标记flag=1
  • 递归过程
    • 遍历所有未使用的字符串
    • 选择下一个能与当前字符串首尾相连的字符串
    • 标记该字符串为已使用,加入路径,递归搜索
    • 回溯操作:撤销当前选择,尝试其他可能性

 输入处理与预处理

int main() {scanf("%d",&n);  // 读取单词数量for(int i=1; i<=n; i++) {cin>>a[i];  // 读取每个单词len[i]=a[i].length();  // 记录单词长度s1[a[i][0]]++;  // 统计首字母出现次数s2[a[i][len[i]-1]]++;  // 统计尾字母出现次数}int start=1;  // 默认从第一个单词开始搜索sort(a+1,a+1+n);  // 对单词进行字典序排序,确保找到的解是字典序最小的

这里使用两个map来统计每个字符作为字符串开头和结尾的次数,

为后续判断欧拉路径做准备。

例如:

  • 如果输入字符串为 ["abc", "cde", "efg"]
  • s1为 {'a':1, 'c':1, 'e':1}
  • s2为 {'c':1, 'e':1, 'g':1}

欧拉路径判断

    char s, t;for(char c='a'; c<='z'; c++) {if(abs(s1[c]-s2[c])==1) {  // 找到入度和出度差为1的字母if(s1[c]-s2[c]==1)s=c;  // 首字母次数比尾字母多1的字母,作为序列的起始字母else if(s2[c]-s1[c]==1)t=c;  // 尾字母次数比首字母多1的字母,作为序列的结束字母}}int cnt=s2[t];  // 结束字母t作为尾字母的次数for(int i=1; i<=n; i++) {if(a[i][0]==s && (a[i][len[i]-1]!=t || cnt!=1)) {start=i;  // 找到以s开头且不以t结尾的单词,或者t作为尾字母仅出现一次的单词,作为起始单词break;}}

这部分代码判断是否存在欧拉路径:

  • 欧拉路径条件
    1. 有向图中,所有节点的入度等于出度,或者
    2. 存在一个节点的出度比入度多 1 (起点),一个节点的入度比出度多 1 (终点),其余节点的入度等于出度
  • s是起点字符,t是终点字符
  • cnt记录终点字符t作为结尾的次数

确定搜索起点

    book[start]=1;  // 标记起始单词已使用now[++sum]=a[start];  // 将起始单词加入当前路径dfs(start,1);  // 从起始单词开始DFS搜索if(flag==0) {  // 如果未找到合法解printf("***\n");return 0;}for(int i=1; i<=n; i++) {  // 输出找到的合法解if(i!=n)cout<<ans[i]<<".";  // 单词之间用点连接elsecout<<ans[i];}printf("\n");return 0;
}

这部分代码确定 DFS 的起始字符串:

  • 优先选择以s开头且不以t结尾的字符串作为起点
  • 如果所有以s开头的字符串都以t结尾,则选择其中任意一个
  • 标记该字符串为已使用,并加入当前路径

输出结果

​if(flag==0)
{printf("***\n");  // 无法形成合法接龙return 0;
}
for(int i=1;i<=n;i++)
{if(i!=n)cout<<ans[i]<<".";  // 用点连接各个字符串elsecout<<ans[i];
}

算法关键点

  1. 欧拉路径判断

    • 通过统计字符的开头和结尾次数,判断是否满足欧拉路径条件
    • 确定起点和终点字符
  2. DFS 回溯搜索

    • 在满足欧拉路径条件的前提下,通过 DFS 找到具体的字符串序列
    • 使用回溯确保所有可能性被探索
  3. 字典序优化

    • 预先对字符串数组排序,确保优先选择字典序小的字符串
    • 起点选择策略保证了在多个可能的起点中选择字典序最小的路径

复杂度分析

  • 时间复杂度:最坏情况下是 O (n!),但通过欧拉路径的判断和起点优化,实际运行效率会高很多
  • 空间复杂度:O (n),主要用于存储字符串和递归调用栈

这个算法巧妙地将字符串接龙问题转化为图论中的欧拉路径问题,并通过 DFS 回溯搜索找到具体解,是一道非常经典的算法题。

———————————————————————————————————————————

好了

到此结束吧

———————————————————————————————————————————

THE END

对了

听说给点赞+关注+收藏的人会发大财哦(o゚▽゚)o  

http://www.dtcms.com/wzjs/72203.html

相关文章:

  • 做网站专业服务营销网
  • 提供广州网站建设seo关键词优化推广报价表
  • 过年做哪个网站致富信息流优化师是干什么的
  • 许昌市住房和城乡建设部网站郑州网站建设制作公司
  • 网站建设工作要点网站服务器速度对seo有什么影响
  • 邢台提供网站建设公司报价网站关键词全国各地的排名情况
  • wordpress 5.1.1漏洞整站优化推广
  • b2b网站大全黄页8禁网络营销专业
  • 西安网站建设易网宣关键词seo培训
  • 如何用电脑主机做网站主机新闻网站排行榜
  • 装修室内设计效果图手机优化大师为什么扣钱
  • 家政网站制作中公教育培训机构官网
  • 快速网站开发介绍域名大全
  • 网站开发的毕设开题报告百度关键词排名联系
  • 做销售的网站网络推广员岗位职责
  • 管理世界万秀服务不错的seo推广
  • 一个人做网站可以做什么百度指数官网数据
  • 药品行业做网站北京网讯百度科技有限公司
  • 如何在百度搜索dw做的网站网页设计与制作案例教程
  • 深圳网站建设售后服务dw网站制作
  • 上海做网站环球网疫情最新消息
  • wordpress 生成sitemap重庆seo团队
  • app官网网站建设百度怎么推广自己的作品
  • 现在网站优化怎么做建设网站的十个步骤
  • 如何做国际网站产品宣传网络顾问
  • 做网站珊瑚橙颜色怎么搭配好看个人博客模板
  • 怎么做自己的网站平台关键词优化公司推荐
  • 淘宝客网站还可以做吗seo网站外包公司
  • 农业银行总行门户网站建设互联网营销是什么意思
  • 西安做网站找哪家公司好百度一下你就知道主页