本文链接http://i.cnblogs.com/EditPosts.aspx?postid=5402042

题意:

  给你N个单词,让你把这些单词排成一个序列,使得每个单词的第一个字母和上一个字单词的最后一个字母相同(栗如:acm,malform,mouse),每个单词最多包含20个小写字母,最多1000个单词。让你输出这个序列,每两个单词之间有个'.',如果有多个解,输出字典序最小的那组解,如果无解输出"***"。关于字典序,个人感觉就是把最后的序列包括'.'在内看成一个字符串,来比较字典序。举个栗子:aa.ab.ba.aba 的字典序小于 aa.aba.ab.ba因为在索引为 5 的地方第一个序列的'.'小于第二个序列的'a',而不是仅仅看每个单词的第一个字母。

思路:

  把每个单词的的两端看成点,把单词看成一条有向边,栗如 atob 表示点 a 到点 b 有一条有向边。那么如果问题有解,则图中一定存在欧拉通路。所以需要首先判断底图是否存在欧拉通路,由单词所建立起来的图是一个有向图,判断有向图是否存在欧拉通路的条件有两个:

第一:底图必须连通,可以用并查集判断;

第二:可以存在2个点出度不等于入度,这两个点中一个出度比入度大1,为路径的起点,另外一个,入度比出度大1,为路径的终点。

如果满足上述两个条件,下来就需要找欧拉路径了,可以采用套圈法, 由于要输出字典序,所以需要对所有单词进行排序,由于涉及到排序,刚好可以用前向星来存储图。

注意:

  第一点:把单词看成边一定是有向的,判定条件不要和无向图搞混。

  第二点:提前排好序,不要在每次选择扩展路径时才选择字典序最小的,容易TLE。

  第三点:如果按照从升序,那么答案应该是反过来的,存在栈中就行了。

  第四点:题目中给的单词是随机的,所以需要找到起点,如果图中存在欧拉回路,即所有点的入度等于出度,那么找到出现的单词中首字母最小的就可以作为路径的起点了。如果不存在欧拉回路,仅存在欧拉通路,即存在确定的起点和确定的终点,那么起点不应该是字母最小的点了,而是确定的那个起点,即出度比入度大 1 的点。

代码:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std; const int maxV = ;
const int maxE = ;
int indeg[maxV + ];//入度
int outdeg[maxV + ];//出度
int head[maxV + ];//确定起点为vi的第一条边的位置
int pre[maxV + ];
int vis[maxE + ];
int E, V;
//并查集
void initPre()
{
for(int i = ; i <= maxV; i++)pre[i] = i;
} int Find(int x)
{
return x == pre[x] ? x : pre[x] = Find(pre[x]);
} void mix(int x, int y)
{
int fx = Find(x);
int fy = Find(y);
if(fx > fy) pre[fx] = fy;
if(fx < fy) pre[fy] = fx;
}
//前向星的结构
struct EdgeNode
{
int from;
int to;
char w[];//单词
}edges[maxE + ]; int minst;
bool isEuler()//是否能形成欧拉通路
{
int flag1 = ;
int flag2 = ;
for(int i = ; i <= maxV; i++)
{
if(indeg[i] != outdeg[i])
{
if(indeg[i] == outdeg[i] + ) flag1++;
else if(indeg[i] == outdeg[i] - ) flag2++,minst = i;//如果存在出度比入度大 1 的点,即为起点
else return false;
}
}
if(flag1 == && flag2 == || flag1 == && flag2 == ) return true;
return false;
} bool isConnct()//连通性判断
{
int cnt = ;
for(int i = ; i <= maxV; i++)
if( (outdeg[i] != || indeg[i] != ) && pre[i] == i)
cnt++;
if(cnt == )return true;
return false;
} stack<int> ans;
void eulerDFS(int now)
{
for(int k = head[now]; edges[k].from == now && k <= E; k++)//优先访问由字典序比较小的单词构成的边
{
if(!vis[k])
{
vis[k] = ;
eulerDFS(edges[k].to);
ans.push(k); //回溯时,压入栈的一定是字典序较大的
}
}
} int cmp(EdgeNode A, EdgeNode B)
{
return strcmp(A.w, B.w) < ;
} int main()
{
int T;
scanf("%d", &T);
while(T--)
{
memset(&edges, , sizeof(EdgeNode));
memset(indeg, , sizeof(indeg));
memset(outdeg, , sizeof(outdeg));
memset(vis, , sizeof(vis));
initPre();
scanf("%d", &E);
minst = maxV + ;
for(int i = ; i <= E; i++)
{
scanf("%s", edges[i].w);
edges[i].from = edges[i].w[] - 'a' + ;
edges[i].to = edges[i].w[strlen(edges[i].w) - ] - 'a' + ;
outdeg[edges[i].from]++;
indeg[edges[i].to]++;
mix(edges[i].from, edges[i].to);
minst = min(minst, edges[i].from);//默认首字母较小的为起点
}
sort(edges + , edges + E + , cmp);//按照字典序升序排序
memset(head, -, sizeof(head));
head[edges[].from] = ;
for(int i = ; i<= E; i++)//构造head数组
{
if(edges[i].from != edges[i - ].from) head[edges[i].from] = i;
}
if(isEuler() && isConnct())
{
eulerDFS(minst);
int flag = ;
while(!ans.empty())
{
printf((flag++) ? ".%s":"%s", edges[ans.top()].w);
ans.pop();
}
printf("\n");
}
else
printf("***\n");
}
return ;
}

POJ 2337 Catenyms (欧拉图)的更多相关文章

  1. POJ 2337 Catenyms(有向欧拉图:输出欧拉路径)

    题目链接>>>>>> 题目大意: 给出一些字符串,问能否将这些字符串  按照 词语接龙,首尾相接  的规则 使得每个字符串出现一次 如果可以 按字典序输出这个字符串 ...

  2. POJ 2337 Catenyms

    http://poj.org/problem?id=2337 题意: 判断给出的单词能否首尾相连,输出字典序最小的欧拉路径. 思路: 因为要按字典序大小输出路径,所以先将字符串排序,这样加边的时候就会 ...

  3. POJ 2337 Catenyms(欧拉回(通)路:路径输出+最小字典序)

    题目链接:http://poj.org/problem?id=2337 题目大意:给你n个字符串,只有字符串首和尾相同才能连接起来.请你以最小字典序输出连接好的单词. 解题思路:跟POJ1386一个意 ...

  4. poj 2337 Catenyms 【欧拉路径】

    题目链接:http://poj.org/problem?id=2337 题意:给定一些单词,假设一个单词的尾字母与还有一个的首字母同样则能够连接.问能否够每一个单词用一次,将全部单词连接,能够则输出字 ...

  5. POJ 2337 Catenyms (有向图欧拉路径,求字典序最小的解)

    Catenyms Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8756   Accepted: 2306 Descript ...

  6. POJ 2337 Catenyms (欧拉回路)

    Catenyms Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8173   Accepted: 2149 Descript ...

  7. POJ 2337 Catenyms(有向图的欧拉通路)

    题意:给n个字符串(3<=n<=1000),当字符串str[i]的尾字符与str[j]的首字符一样时,可用dot连接.判断用所有字符串一次且仅一次,连接成一串.若可以,输出答案的最小字典序 ...

  8. Poj 2337 Catenyms(有向图DFS求欧拉通路)

    题意: 给定n个单词, 问是否存在一条欧拉通路(如acm,matal,lack), 如果存在, 输出字典序最小的一条. 分析: 这题可以看作http://www.cnblogs.com/Jadon97 ...

  9. Day 4 -E - Catenyms POJ - 2337

    A catenym is a pair of words separated by a period such that the last letter of the first word is th ...

随机推荐

  1. (转\整)UE4游戏优化 多人大地型游戏的优化(一)游戏线程的优化

    施主分享随缘,评论随心,@author:白袍小道 小道暗语: 1.因为小道这里博客目录没自己整,暂时就用随笔目录结构,所以二级目录那啥就忽略了.标题格式大致都是(原or转) 二级目录 (标题) 2.因 ...

  2. crontab-用于设置周期性被执行的指令

    一个很好用的工具. 参考文章: [入门] http://baike.baidu.com/view/1229061.htm [进阶] http://blog.csdn.net/tianlesoftwar ...

  3. Ubuntu16.04安装openCV的问题集合

    Q1 下列软件包有未满足的依赖关系:   libtiff4-dev : 依赖: libjpeg-dev  E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系. 上网查了 ...

  4. vue 三目运算

    :class="followed ? 'btn-success':'btn-secondary'"

  5. php学习ing

    cmd运行,表示在本地d:/php/workspace下文件映射在127.0.0.1的8080端口下,-S -t不要忘记 php -S 127.0.0.1:8080 -t E:\class_manag ...

  6. BZOJ 2186 沙拉公主的困惑

    2186: [Sdoi2008]沙拉公主的困惑 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 3397  Solved: 1164 [Submit] ...

  7. [洛谷P4149][IOI2011]Race

    题目大意:给一棵树,每条边有边权.求一条简单路径,权值和等于$K$,且边的数量最小. 题解:点分治,考虑到这是最小值,不满足可减性,于是点分中的更新答案的地方计算重复的部分要做更改,就用一个数组记录前 ...

  8. [洛谷P4074][WC2013]糖果公园

    题目大意:给一棵$n$个节点的树,每个点有一个值$C_i$,每次询问一条路径$x->y$,求$\sum\limits_{c}val_c\times \sum\limits_{i=1}^{cnt_ ...

  9. vue实现多个元素或多个组件之间动画效果

    多个元素的过渡 <style> .v-enter,.v-leave-to{ opacity: 0; } .v-enter-acitve,.v-leave-active{ opacity: ...

  10. 【HDU 3336 Count the string】

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission( ...