有向图,无向图的欧拉回路和欧拉通路poj 2337

原创 2013年12月06日 04:31:06

1. 欧拉回路,欧拉通路定义与判断

定义:

   欧拉回路:从图的某一个顶点出发,图中每条边走且仅走一次,最后回到出发点;如果这样的回路存在,则称之为欧拉回路。 
   欧拉路径:从图的某一个顶点出发,图中每条边走且仅走一次,最后到达某一个点;如果这样的路径存在,则称之为欧拉路径

判断:
     无向图欧拉回路判断:所有顶点的度数都为偶数。
     有向图欧拉回路判断:所有顶点的出度与入读相等。

     无向图欧拉路径判断: 之多有两个顶点的度数为奇数,其他顶点的度数为偶数。
     有向图欧拉路径判断: 至多有两个顶点的入度和出度绝对值差1(若有两个这样的顶点,则必须其中一个出度大于入度,另一个入度大于出度),其他顶点的入度与出度相等。
判断有向图和无向图是否存在欧拉回路和欧拉路径非常简单, 就是要注意要用并查集统计图的联通分量个数。保证联通分量的个数为1个上述算法才成立。

算法:
 
     下面给出求欧拉回路(路径)的伪代码:
Procedure Euler-circuit (start);
Begin
  For 顶点start的每个邻接点v Do
  If 边(start,v)未被标记 Then Begin
	将边(start,v)作上标记;
	将边(v,start)作上标记;                   //1
	Euler-circuit (v);
	将边加入栈;
  End;
End;

其中图可以用临界矩阵表示也可以用临界表或者边表表示。最后依次去除栈中的边或者顶点(按照具体的需求)得到欧拉回路或欧拉路径(该为代码针对无向图, 如果是有向图就去掉//1行)。如果存在入度和出度差1的顶点(无向图是顶点度数为奇数的顶点) 应该从出度比入度大1的顶点开始搜索。

接下来用Poj 2337 为例子  给出实现代码:

题目大意:输入n个单词,每个单词都形成一条从该单词首字母到尾字母的边,单词尾字母要与下一个单词首字母相同,若可以组成这样的路,即可以组成这样一条连着的单词串,输出路径(单词串),若有多条,则要按字典顺序输出,找不到路则输出***。
   
代码:
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAX_N = 1010;
const int MAX_VERT = 27;
struct Edge{
  int v, next;
  bool vis;
  char str[MAX_VERT];
};

struct Dict{
  char str[MAX_VERT];
};

Dict dict[MAX_N];
Edge edge[MAX_N * MAX_N / 2];
int adj[MAX_VERT];
char res[MAX_N][MAX_VERT];
int pre[MAX_VERT], rank[MAX_VERT];
int in[MAX_VERT], out[MAX_VERT];
bool used[MAX_VERT];
int n, edge_num;
int res_cnt;
bool cmp(const Dict& a, const Dict& b)
{
  return strcmp(a.str, b.str) >= 0;
}

void add_edge(int u, int v)
{
  edge[edge_num].vis = false;
  edge[edge_num].v = v;
  edge[edge_num].next = adj[u];
  adj[u] = edge_num++;
}

void init()
{
  for(size_t i = 0; i < MAX_VERT; ++i)
  {
    pre[i] = i;
    rank[i] = 0;
  }
}

int find(int x)
{
  return x == pre[x] ? x : pre[x] = find(pre[x]);
}

void Union(int x, int y)
{
  x = find(x);
  y = find(y);
  if(x == y)
    return;
  if(rank[x] > rank[y])
  {
    pre[y] = x;
  }
  else 
  {
    if(rank[x] == rank[y])
      rank[y]++;
    pre[x] = y;
  }
}
//judge Euler loop and Euler path in direction graph
//if the out and in degree are same. There exist a Euler loop and return any vertex as start
//if there have two vertex out and in degree not same. And one's out degree minus in degree equal 1
//and another vertex's in degree minus in degress equal 1. Else return -1 represent no Euler loop or path exist
int judge_euler()
{
  int comp_num = 0;
  int in_cnt = 0, out_cnt = 0;
  int res_idx = -1;
  for(size_t i = 0; i < MAX_VERT; ++i)
  {
    if(used[i])
    {
      if(i == find(i))//count the number of the components
        comp_num++;
      if(in[i] != out[i])
      {
        if(in[i] - out[i] == 1)
          in_cnt++;
        else if(out[i] - in[i] == 1)
        {
          out_cnt++;
          res_idx = i;
        }
        else 
          return -1;
      }
    }
  }
  if(comp_num != 1)//if there have more or less than 1 component return fail
    return -1;
  if(!((in_cnt == 1 && out_cnt == 1) || (in_cnt == 0 && out_cnt == 0)))
    return -1;
  if(res_idx == -1)
  {
    for(size_t i = 0; i < MAX_VERT; ++i)
    {
      if(out[i] > 0)
      {
        res_idx = i;
        break;
      }
    }
  }
  return res_idx;
}
//calculate Euler path 
void euler(int now, int idx)
{
  for(int i = adj[now]; i != -1; i = edge[i].next)
  {
    if(!edge[i].vis)
    {
      edge[i].vis = true;
      euler(edge[i].v, i);
    }
  }
  if(idx != -1)
    strcpy(res[res_cnt++], dict[idx].str);
}

int main()
{
  int t;
  scanf("%d", &t);
  while(t--)
  {
    memset(in, 0, sizeof(in));
    memset(out, 0, sizeof(out));
    memset(adj, -1, sizeof(adj));
    memset(used, false, sizeof(used));
    init();
    scanf("%d", &n);
    for(size_t i = 0; i < n; ++i)
    {
      char tmp[MAX_VERT];
      scanf("%s", &dict[i].str);
    }
    sort(dict, dict + n, cmp);
    edge_num = 0;
    res_cnt = 0;
    for(size_t i = 0; i < n; ++i)
    {
      int u = dict[i].str[0] - 'a';
      int v = dict[i].str[strlen(dict[i].str) - 1] - 'a';
      add_edge(u, v);
      used[u] = used[v] = true;
      in[v]++;
      out[u]++;
      int x = find(u);
      int y = find(v);
      if(x != y)
        Union(x, y);
    }
    int start = judge_euler();
    if(start != -1)
    {
      euler(start, -1);
      for(int i = res_cnt - 1; i >= 0; --i)
      {
        printf("%s", res[i]);
        if(i != 0)
          printf(".");
      }
      printf("\n");
    }
    else 
      printf("***\n");
  }
}





有向图欧拉回路

Watchcow Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 5902   Accep...
  • u012859437
  • u012859437
  • 2014年07月19日 16:31
  • 1136

有向图中欧拉回路的求法

首先是欧拉回路的判断 在无向图中的欧拉回路 每个顶点的度都是偶数 且图为连通图 在判断连通性的时候可以使用并查集来判断图的连通性 也可以使用dfs或bfs来判断 不过运行速度会慢一点 在有...
  • HE19930303
  • HE19930303
  • 2015年07月28日 14:12
  • 421

有向图的欧拉回路及欧拉道路

//有向图 //欧拉回路:1.图连通2.每个点的入度等于出度 //欧拉道路:1.图连通2.每个点的入度等于出度或有两个点入度不等于出度,且一个点出度比入度大一(起点),另一个点入度比出度小一(终点)如...
  • fengsigaoju
  • fengsigaoju
  • 2015年08月02日 19:57
  • 512

有向图的欧拉回路

  • 2013年12月25日 13:15
  • 36KB
  • 下载

一笔画问题(并查集+无向欧拉图)

一笔画问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,...
  • baidu_23955875
  • baidu_23955875
  • 2015年07月10日 16:21
  • 573

HIHO1176(无向图欧拉路)

hihoCoder1176题【没有账号登不进去的】 其实,也没有什么好说的,并查集判断无向图的连通性,再根据欧拉路的充要条件判断就可以解决本题了,也算是水题#include #include #...
  • huziyang9
  • huziyang9
  • 2015年08月03日 10:30
  • 357

计蒜客 判定欧拉回路 (利用并查集实现有向图欧拉回路的判断)

题目链接:https://www.jisuanke.com/course/615/28228 题目思路:利用并查集判断是否为连通图,然后再利用欧拉图的相关的性质进行判断。 代码: #in...
  • qq_29980371
  • qq_29980371
  • 2017年09月06日 21:00
  • 155

有向图欧拉回路 Codeforces508D Tanya and Password

欧拉回路图上瘾中,总结下用法 对于必须要用上某个单词,就取这个单词的左部分为L,右部分为R,形成一个从L到R的有向图 然后再判断是否符合欧拉回路图,即验证所有点的出度和入度,验证方法如下: 1.如...
  • qwb492859377
  • qwb492859377
  • 2015年06月30日 21:47
  • 801

有向图欧拉回路 hihoCoder1182 欧拉路·三

终于把欧拉回路的3个例题做完了,没想到竟然可以这样建图避开求曼哈顿回路。 把数字当成边,而不是点。这样只需要求一次欧拉回路(相当于所有的数字都用上),就能轻松解决问题了! #include #in...
  • qwb492859377
  • qwb492859377
  • 2015年06月30日 19:46
  • 765

有向图欧拉回路条数-BEST定理

教学香肠系列……给定一张所有点入度=出度的有向图,求欧拉回路条数。 n≤500n\leq 500为了避免出现重复,对于这个无向图,我们先确定一条11号节点出发的起始边。找一个以11号点为根的内向树(...
  • PoPoQQQ
  • PoPoQQQ
  • 2017年08月09日 21:30
  • 889
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:有向图,无向图的欧拉回路和欧拉通路poj 2337
举报原因:
原因补充:

(最多只允许输入30个字)