本文链接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. 《Cracking the Coding Interview》——第1章:数组和字符串——题目8

    2014-03-18 02:12 题目:判断一个字符串是否由另一个字符串循环移位而成. 解法:首先长度必须相等.然后将第一个串连拼两次,判断第二个串是否在这个连接串中. 代码: // 1.8 Assu ...

  2. ADB连接手机遇到的问题:list of devices attached

    今天工作时想尝试一下使用ADB无线连接手机,结果遇到了下面这样的问题,浪费了几十分钟的时间,挺闹心的,因此想分享出来... 首先 第一步:使用USB数据线连接手机,手机弹出选项时,选择仅充电,然后wi ...

  3. mysql数据库的日常使用

    mysql管理: 首先记得你只要改了权限设置,请记得重启下mysql数据库服务. 适用环境全部是linux环境下适用了. 1.查看mysql服务是否启动 ps -aux | grep mysqld 如 ...

  4. (原)Skeletal With DirectX12

    @author: 白袍小道 @来源: Advanced Animation with DirectX, 游戏引擎架构         (暗影不解释连招)     引言: 3D模型动画的基本原理是让模型 ...

  5. Anaconda基本使用

    anaconda常用使用命令 显示安装程序包列表 conda list 选择其它的源 conda config --add channels https://mirrors.tuna.tsinghua ...

  6. Ext JS 的一个非常好的学习网站

    起飞网 http://www.qeefee.com/zt-extjs 发现一个非常好的学习ExtJS的中文网站

  7. webpack + less

    使用less需要安装 'style-loader','css-loader','less-loader' 三个loader. 安装之后在webpack.config.js配置 const path = ...

  8. [hdu6437]Problem L. Videos

    题目大意:有$n$个小时,有$m$个节目(每种节目都有类型$0/1$),有$k$个人,一个人连续看相同类型的节目会扣$w$快乐值. 每一种节目有都一个播放区间$[l,r]$.每个人同一时间只能看一个节 ...

  9. webpack的css,less,sass中使用绝对路径

    用法: 使用~表示绝对路径,如下: @import "~otherfile.scss" .yourClass { background: url('~img/wallpaper.p ...

  10. python带header

    headers = { "Accept":"text/html,application/xhtml+xml,application/xml;", "A ...