判断欧拉路径是否存在及求出字典序最小的欧拉路径问题(如果存在)。

将字符串的第一个字母和最后一个字母间连边,将字母看成点,最多可能有26个点(a-z),如果有欧拉路径,还要判断是否有欧拉回路,如果有,则需要找一个字典序最小的点开始生成这条链,否则以起点开始生成链,起点即为出度比入度大1的点。

欧拉路径是否存在的判定:

1.全部点在一个联通块                               ----用并查集判联通块的数量
2.所有点出度入度相等                               ----in[],out[]记录出度与入度
3.或者有一个出度比入度小1,另一个出度比入度大1(源点与汇点)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#define Mod 1000000007
using namespace std;
#define N 2007 string ss[N]; struct node
{
int u,v,next;
string w;
}G[N]; int first[],fa[],in[],out[],vis[];
int tot,k,start;
int evis[N];
string ans[N]; void init()
{
int i;
for(i=;i<;i++)
fa[i] = i;
tot = ;
memset(in,,sizeof(in));
memset(out,,sizeof(out));
for(i=;i<=;i++)
{
G[i].u = G[i].v = G[i].next = ;
G[i].w = "";
}
memset(first,-,sizeof(first));
memset(vis,,sizeof(vis));
memset(evis,,sizeof(evis));
for(int j=;j<=;j++)
ans[j] = "";
} int findset(int x)
{
if(x != fa[x])
fa[x] = findset(fa[x]);
return fa[x];
} int cmp(string ka,string kb)
{
return ka>kb;
} void addedge(int u,int v,string w)
{
G[tot].u = u;
G[tot].v = v;
G[tot].w = w;
G[tot].next = first[u];
first[u] = tot++;
out[u]++;
in[v]++;
vis[u] = vis[v] = ;
int fx = findset(u);
int fy = findset(v);
if(fx != fy)
fa[fx] = fy;
} int Euler_Path()
{
int block = ,i;
int O = ;
int I = ;
start = -;
for(i=;i<;i++)
{
if(vis[i]) //涉及到的字母
{
int fk = findset(i);
if(fk == i)
block++;
if(block > )
return false;
if(in[i] == out[i]+) //入大出,奇度数点
I++;
else if(in[i]+ == out[i]) //出大入,奇度数点
O++,start = i;
else if(in[i] != out[i])
return false;
}
}
if(block != )
return false;
if((O == I && O == ) || (O == I && O == )) //没有奇度数点或者只有源点和汇点是奇度数点
{
if(start == -) //没有找到起点,是欧拉回路
{
for(i=;i<;i++)
{
if(vis[i] && out[i] > ) //找字典序最小的字母做起点
{
start = i;
return true;
}
}
}
//如果已找到起点,则不能是欧拉回路
if(O == I && O == )
return true;
return false;
}
return false;
} void dfs(int v,int flag)
{
for(int e=first[v];e!=-;e=G[e].next)
{
if(!evis[e]) //边没被访问
{
evis[e] = ;
dfs(G[e].v,e);
}
}
if(flag != -)
ans[k++] = G[flag].w;
} int main()
{
int t,i,j,n;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&n);
for(i=;i<=n;i++)
cin>>ss[i];
sort(ss+,ss+n+,cmp);
//qsort(ss+1,n,28,cmp);
for(i=;i<=n;i++)
{
int u = ss[i][]-'a';
int v = ss[i][ss[i].length()-]-'a';
addedge(u,v,ss[i]);
}
if(Euler_Path())
{
k = ;
dfs(start,-);
cout<<ans[k-];
for(i=k-;i>=;i--)
cout<<"."<<ans[i];
printf("\n");
}
else
puts("***");
}
return ;
}

UESTC 917 方老师的分身IV --求欧拉路径的更多相关文章

  1. UESTC 901 方老师抢银行 --Tarjan求强连通分量

    思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个D ...

  2. UESTC 914 方老师的分身I Dijkstra

    题意:求有向图的往返最短路的最长长度. 分析:求第一次到所有点的距离可以用一次Dijkstra求最短路求出来.考虑回来的路,想想就知道,从每个点回来的路即为将边的方向反转再求一次最短路后的结果. 所以 ...

  3. UESTC 915 方老师的分身II --最短路变形

    即求从起点到终点至少走K条路的最短路径. 用两个变量来维护一个点的dis,u和e,u为当前点的编号,e为已经走过多少条边,w[u][e]表示到当前点,走过e条边的最短路径长度,因为是至少K条边,所以大 ...

  4. UESTC 916 方老师的分身III --拓扑排序

    做法: 如果有a<b的关系,则连一条a->b的有向边,连好所有边后,找入度为0的点作为起点,将其赋为最小的价值888,然后其所有能到的端点,价值加1,加入队列,删去上一个点,然后循环往复, ...

  5. UESTC_方老师的分身 II CDOJ 915

    方老师的分身 II Time Limit: 10000/5000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submi ...

  6. UESTC 898 方老师和缘分 --二分图匹配+强连通分量

    这题原来以为是某种匹配问题,后来好像说是强连通的问题. 做法:建图,每个方老师和它想要的缘分之间连一条有向边,然后,在给出的初始匹配中反向建边,即如果第i个方老师现在找到的是缘分u,则建边u-> ...

  7. UESTC - 900 方老师炸弹 —— 割点

    题目链接:https://vjudge.net/problem/UESTC-900   方老师炸弹 Time Limit: 4000/2000MS (Java/Others)     Memory L ...

  8. UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数

    Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u], ...

  9. UESTC 884 方老师的专题讲座 --数位DP

    定义:cnt[L][K]表示长度为L,最高位为K的满足条件C的个数. 首先预处理出cnt数组,枚举当前长度最高位和小一个长度的最高位,如果相差大于2则前一个加上后一个的方法数. 然后给定n,计算[1, ...

随机推荐

  1. mybatis中自建的类型别名

    在使用mybatis过程中经常用到类型别名,除了我们自己新建的别名外,mybatis还自带了很多类型别名和java中的类型的映射,下面先看一个自建的别名的配置 <typeAliases> ...

  2. ArcGIS补丁包下载

    http://zhihu.esrichina.com.cn/?/feature/patchdownload

  3. RecyclerView和ScrollView嵌套使用

    我们的recyclerView有多个layoutmanager,通过重写layoutmanager的方法就可以让recyclerView和ScrollView嵌套了.但是请注意,如果recyclerV ...

  4. 为什么Android应该根据屏幕分辨率来加载不同的图片文件

    1.图片在xxhdpi,手机是hdpi的 我们有一个手机是hdpi的.我们还有一个图片,我们把他放在xxhdpi下.当手机显示的时候,系统会去hdpi中找,发现没有图片,最终在xxhpi中找到.终于找 ...

  5. 在Mac上配置Android adb命令

    一 adb定义: adb(android debug bridge)是android系统中的一种命令行工具,通过它可以和android设备或模拟器通信. 二 在Mac上的配置过程 启动终端 进入当前用 ...

  6. iOS内存管理(二)之深拷贝和浅拷贝

    对象拷贝(复制对象) 1.复制对象顾名思义,复制一个对象作为副本,它会开辟一块新的一块内存(堆内存)来存储副本对象,就像复制文件一样.即源对象和副本对象是两块不同的内存区域.   2.NSObject ...

  7. iOS背景模糊效果3中方法总结

    1.首先得把界面转化成图片,给uiview加一个类目如下: #import "UIView+Screen.h" @implementation UIView (Screen) // ...

  8. Android App的架构设计:从VM、MVC、MVP到MVVM

    随着Android应用开发规模的扩大,客户端业务逻辑也越来越复杂,已然不是简单的数据展示了.如同后端开发遇到瓶颈时采用的组件拆分思想,客户端也需要进行架构设计,拆分视图和数据,解除模块之间的耦合,提高 ...

  9. (第五章)java面向对象之this的作用总结

    this关键字总是指向调用该方法的对象. this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的对象只能是当前类的(在那个类中就是那个类), ...

  10. android媒体文件扫描

    项目中可能有这样的需求:下载或导入.导出的图片.音乐等媒体文件,需要马上能在图库或本地视屏播放器中显示出来,或者要能在媒体数据库中查询到媒体文件的相关信息,这时我们就得主动通知系统扫描新的媒体文件了. ...