[欧拉回路]

define : 奇点——度数是奇数;
无向图:
1.是连通的,
2最多只有两个奇点,
则一定存在欧拉道路。
如果有两个奇点,则必须从其中一个奇点出发,另一个奇点终止;
如果无奇点,则可以从任意点出发,最终一定会回到该点(称为欧拉回路)。
有向图的结论:
1.最多两个点的入度不等于出度,
2.必须是其中一个点的出度恰好比入度大1(把它作为起点),另一个的入度比出度大1(把它作为终点)。
当然,还有一个前提条件:在忽略边的方向后,图必须是连通的。

stack<node>q;
void euler(int u){
for(int v = 0; v < n; v++) if(G[u][v] && !vis[u][v]) {
  vis[u][v] = vis[v][u] = 1;
  euler(v);
  q.push(node(u,v));
  }
}

注意:
上面是用邻接矩阵存的图。G【】【】。
但如果需要打印的是欧拉道路,在主程序
中调用时,参数必须是道路的起点。另外,打印的顺序是逆序的,因此在真正使用这份代码
时,应当把把边(u,v)压入一个栈内。
尽管上面的代码只适用于无向图,但不难改成有向图:把vis[u][v] = vis[v][u] = 1改成
vis[u][v]即可。
改成邻接表

void euler(int u)
{
   for(int i = h [u] ;i ;i = e[i].nxt)
   {
     int v = e[i].to;
     if(!e[i].vis)
     {
     euler(v);q.push(node(u,v));
     }
   }
}

例题

UVA10129 Play on Words
大意:
输入n(n≤100000)个单词,是否可以把所有这些单词排成一个序列,使得每个单词的
第一个字母和上一个单词的最后一个字母相同(例如acm、malform、mouse)。每个单词最
多包含1000个小写字母。输入中可以有重复单词

任务:判断是否有欧拉回路。分成两个小任务;
1.最多两个点的入度不等于出度.必须是其中一个点的出度恰好比入度大1(把它作为起点),另一个的入度比出度大1(把它作为终点)。
2.判断图的连通性,我用的dfs
code

    bool vis[N];
//is connext ?
void dfs(int u)
{
    for (int i = h[u];i;i = e[i].nxt)
    {
        int v = e[i].to;
        if(!vis[v])
        {
            vis[v] = 1;
            dfs(v);
        }
    }
}
bool checkdfs()
{
    for (int i = 0;i < N ;i++)
    {
        if(in[i]&&!vis[i])return 0;
        else if(out[i]&&!vis[i])return 0;
    }
    return 1;
}
//欧拉in、和out在建图的时候记录
bool ok = 1;int n1 = 0,n2 = 0;
        for (int i = 0;i < N;i++)
        {
            if(!ok)break;
            if(in[i] != out[i])
            {
                if(in[i] == out[i]+1)n1++;
                else if(out[i] == in[i] + 1)n2++;
                else {ok = 0;break;}
            }
        }
        if(n1 && n2 && n1 + n2 > 2)ok = 0;

猜你喜欢

转载自blog.csdn.net/k42946/article/details/81607936