-
描述
-
给你一些单词,请你判断能否把它们首尾串起来串成一串。
前一个单词的结尾应该与下一个单词的道字母相同。
如
aloha
dog
arachnid
gopher
tiger
rat
可以拼接成:aloha.arachnid.dog.gopher.rat.tiger
-
输入
-
第一行是一个整数N(0<N<20),表示测试数据的组数
每组测试数据的第一行是一个整数M,表示该组测试数据中有M(2<M<1000)个互不相同的单词,随后的M行,每行是一个长度不超过30的单词,单词全部由小写字母组成。
输出
-
如果存在拼接方案,请输出所有拼接方案中字典序最小的方案。(两个单词之间输出一个英文句号".")
如果不存在拼接方案,则输出
***
样例输入
-
2 6 aloha arachnid dog gopher rat tiger 3 oak maple elm
样例输出
-
aloha.arachnid.dog.gopher.rat.tiger ***
-
第一行是一个整数N(0<N<20),表示测试数据的组数
此题是以字符串的首尾字母为节点的,以字符串本身为边的。
有向图判定是否存在欧拉通路,并输出欧拉路径。
有向图定理:有向图D存在欧拉通路的充要条件是:D为有向图,D的基图(就是图D对应的无向图)连通,并且每个节点的出度等于它的入度;或者除两个节点外,其他节点的出度与入度都相等,而这两个节点中,其中一个节点的出度与入度的差为1(out-in=1),另一个顶点的出度与入度之差为-1(out-in=-1)
推论:
1. 当有向图D,除了出度,入度之差为1,-1的两个节点之外,其余顶点的出度与入度相等时,D的有向欧拉通路必以出度与入度之差为1的顶点作为始点,以出度与入度之差为-1的顶点作为终点。
2. 当有向图D的所有顶点的出度与入度都相等时,D中存在有向欧拉回路。
3. 有向图D为有向欧拉图的充要条件是D的基图为连通图,并且所有节点的出、入度都相等。
因此此题的解题方法分为三步:
1.判断有向图G对应的无向图是连通的。
2.统计每个节点的入度与出度,要求所有节点的出度与入度都相等 或 其中一个节点的出度与入度的差为1,另一个节点的出度与入度之差为-1,其他顶点的出度与入度都相等。
3.满足以上两个条件,递归求欧拉路径并输出。
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<string.h>
#include<algorithm>
#define PI 3.1415926
using namespace std;
const int maxn = 1003;
int father[30]; ///并查集
int ans[maxn];
int in[30]; ///存放每个节点的入度
int out[30]; ///存放每个节点的出度
string word[maxn]; ///用来存放单词
int N,k; ///单词数
int chose[30]; ///用来判断哪些小写字母出现了
struct Edge ///以单词为边,以单词的首尾字母为节点
{
int s; ///起点
int d; ///终点
bool flag; ///标记当前单词是否用过
}edge[maxn];
void make_set() ///并查集初始化
{
for(int i = 0; i < 30; i++)
father[i] = i;
}
int find_set(int x) ///找x所在的集合
{
while(x != father[x])
{
x = father[x];
}
return x;
}
void union_set(int x,int y) ///合并两个集合
{
father[x] = y;
}
bool IsConnection() ///判断图是否连通
{
int num = 0;
///chose用来标记图中存在哪些小写字母
for(int i = 0; i < 26; i++)
{
if(chose[i]) ///是图中的节点
{
if(father[i]==i)
{
num++;
}
}
}
if(num == 1) return true;
else return false;
}
void DFS(int start)
{
for(int i = 0; i < N; i++)
{
if(edge[i].s == start)
{
if(!edge[i].flag)
{
edge[i].flag = true;
DFS(edge[i].d);
ans[k++] = i;
///求出后答案是倒着的
}
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>N; ///N个单词
for(int i = 0; i < N; i++)
{
cin>>word[i];
}
memset(chose,0,sizeof(chose)); ///题目中出现的单词
memset(out,0,sizeof(out)); ///各个点的入度赋值为0
memset(in,0,sizeof(in)); ///各个点的出度赋值为0
make_set();
///因为答案最后要的是字典序最小的,因此要先对字符排序。
sort(word,word+N);
for(int i = 0; i < N; i++)
{
int len = word[i].length();
int s = word[i][0]-'a';
int d = word[i][len-1]-'a';
chose[s] = chose[d] = 1;
edge[i].s = s;
edge[i].d = d;
edge[i].flag = false;
out[s]++;
in[d]++;
int fs = find_set(s);
int fd = find_set(d);
if(fs != fd)
union_set(fs,fd);
}
int start = edge[0].s; ///假设起点是这个字符
int num1 = 0,num2 = 0;
bool flag = true;
for(int i = 0; i < 26; i++)
{
if(chose[i])
{
if(in[i]==out[i]) continue;
else if(out[i]-in[i]==1)
{
start = i;
num1++;
}
else if(out[i]-in[i]==-1)
{
num2++;
}
else
{
flag = false;
break;
}
}
}
///三个条件都成立,欧拉通路存在。
if(flag&&((num1==0&&num2==0)||(num1==1&&num2==1))&&IsConnection())
{
k = 0;
DFS(start);
cout<<word[ans[k-1]];
for(int i = k-2; i >= 0; i--)
{
cout<<"."<<word[ans[i]];
}
cout<<endl;
}
else
{
cout<<"***"<<endl;
}
}
return 0;
}

本文介绍了一种基于欧拉路径的算法,用于解决特定类型的单词串接问题。通过构造一个有向图,利用图的连通性和节点出入度特性来寻找可能的串接方案,并输出字典序最小的解决方案。
&spm=1001.2101.3001.5002&articleId=71107836&d=1&t=3&u=c660668a6fc54430b790ab936613b558)
395

被折叠的 条评论
为什么被折叠?



