本文链接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. CodeIgniter学习笔记五:分页,文件上传,session,验证码

    一.分页 示例代码: //装载类文件 $this -> load -> library('pagination'); $controller = $this->router-> ...

  2. 【Lowest Common Ancestor of a Binary Tree】cpp

    题目: Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. Accor ...

  3. 问题:JFinal框架使用FreeMarker渲染视图报错

    本人用的是JFinal-3.4. 问题描述: 在JFinal框架中使用FreeMarker渲染视图时,报 Caused by: java.lang.ClassNotFoundException: fr ...

  4. IDEA调试快捷键

    F9            resume programe 恢复程序 F8            Step Over 相当于eclipse的f6      跳到下一步 Ctrl+Shift+F,全局查 ...

  5. Python全栈工程师 (exercises)

    # 1:给定一个数,判断他是正数,负数,还是0 a = int(input("请输入一该个整数")) if a == 0: print(a, "是0") eli ...

  6. echarts 柱状图下钻功能

    var drillDown = {   getOption : function () {   var option = null;   option = {   title: {   text: ' ...

  7. php 数据库内容增删改查----增

    首先,建立一个主页面(crud.php) <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  8. android自定义控件属性

    有两种方法为自定义的控件设置属性 . 来自为知笔记(Wiz)

  9. PHP 自制分页类

    思路: 通过给页面url传递get参数,来控制每页的sql查询(mysql关键词:limit),实现分页查询 代码: class getpage{ public $pagenum; public $p ...

  10. 发现一个form小问题

    在使用编辑器及框架时,form表单如果在太靠内的div层里,就取不到textarea的post值,具体原因位置,可能跟框架的CSS有关