前向星——附带欧拉回路求解

本文介绍了前向星数据结构在图论中的应用,特别强调了其在构建和遍历图上的高效性。同时,文章详细讨论了欧拉通路和欧拉回路的概念,以及在无向图和有向图中的存在条件。提供了基于DFS的欧拉回路求解方法,包括Fleury算法,阐述了如何通过前向星来寻找路径。

前向星

  • 用head[i]记录以i为边集在数组中的第一个存储位置
  • 通过struct的next找到下一个位置,是一个变形的邻接表
  • 时间空间复杂度都很小,占用很少的额外空间,是目前建图和遍历效率最高的储存方式

推荐文章:http://blog.youkuaiyun.com/acdreamers/article/details/16902023

构建与遍历代码:
int head[Max_N]={-1};
struct Edge{
    int to,next,w;
}edge[Max_M];
int main()
{
    memset(s,0,sizeof s);       //若从0开始,memset为-1
    for(int i=1;i<=m;i++)       //m为边数
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        edge[i].to=b;
        edge[i].w=c;
        edge[i].next=head[a];
        head[a]=i;
    }
    for(int i=1;i<=n;i++)      //n为顶点数
    {
        for(int k=head[i];k!=0;k=edge[k].next)
        {
            cout<<i<<" "<<edge[k].to<<endl;
        }
    }
    return 0;
}

欧拉回路的求解

  • 欧拉通路: 通过图中每条边且只通过一次,并且经过每一顶点的通路
  • 欧拉回路: 通过图中每条边且只通过一次,并且经过每一顶点的回路
  • 有向图的基图:忽略有向图所有边的方向,得到的无向图称为该有向图的基图。
  • 无向图
    设G是连通无向图,则称经过G的每条边一次并且仅一次的路径为欧拉通路;
    如果欧拉通路是回路(起点和终点是同一个顶点),则称此回路是欧拉回路
    具有欧拉回路的无向图G成为欧拉图
    有向图
    (1)设D是有向图,D的基图连通,则称经过D的每条边一次并且仅有一次的有向路径为 有向欧拉通路
    (2)如果有向欧拉通路是有向回路,则称此有向回路为 有向欧拉回路
    (3)具有有向欧拉回路的图D称为有向欧拉图
    定理
    无向图G存在欧拉通路的充要条件是:G为连通图,并且G仅有两个奇度结点(度数为奇数的顶点)或者无奇度结点。
    推论
    (1) 当G是仅有两个奇度结点的连通图时,G的欧拉通路必以此两个结点为端点;
    (2)当G是无奇度结点的连通图时,G必有欧拉回路
    (3)G为欧拉图(存在欧拉回路)的充分必要条件是 G为无奇度结点的连通图

  • (有向图) 定理
    有向图D存在欧拉通路的充要条件是:D为有向图,D的基图连通,并且所有顶点的出度与入度相等;或者 除两个顶点外,其余顶点的出度与入度都相等,而这两个顶点中一个顶点的出度与入度之差为1,另一个顶点的出度与入度之差为-1.
    推论
    (1)当D除出、入度之差为1,-1的两个顶点之外,其余顶点的出度与入度相等时,D的有向欧拉通路必以出、入度之差为1的顶点作为始点,以出、入度之差为-1的顶点作为终点。
    (2)当D的所有顶点的出、入度都相等时,D中存在有向欧拉回路。
    (3)有向图D为有向欧拉图的充要条件是 D的基图为连通图,并且所有顶点的出、入度都相等。

两种方法:(1)DFS搜索 (Fleury)佛罗莱算法
(1)DFS搜索 思想求解欧拉回路的思路为:利用欧拉定理判断出一个图存在欧拉通路或欧拉回路后,选择一个正确的起始顶点,用DFS算法遍历所有的边(每条边只遍历一次),遇到走不通就回退。在搜索前进方向上将遍历过的边按顺序记录下来。这组边的排列就组成了一条欧拉通路或回路。
(2) (Fleury)佛罗莱算法
设G为一个无向欧拉图,求G中一条欧拉回路的算法如下:
(1) 任取G中一顶点v0,令P0=v0;
(2)假设沿Pi=v0e1v1e2v2……eivi走到顶点vi,按下面方法从E(G)-{e1,e2,…,ei}中选ei+1。
ei+1与vi相关联
除非无别的边可供选择,否则ei+1不应该是Gi=G-{e1,e2,…,ei}中的桥。
(3)当(2)不能再进行时算法停止。
可以证明的是,当算法停止时,所得到的简单回路Pm=v0e1v1e2v2……emvm,(vm=v0)为G中一条欧拉回路。

以上知识点来源自百度,侵删

 void dfs(int x)
 {
     t.push(x);
     for(int i=1;i<=n;i++)
     {
         if(path[x][i])         //找到连边并删除,从该点继续dfs
         {
             path[x][i]=path[i][x]=0;//删除此边
             dfs(i);
             break;
         }
     }
 }
 void  Fleury(int x)
 {
     t.push(x);
     while(!t.empty())
     {
         int b=0;
         for(int i=1;i<=n;i++)
         {
             if(path[t.top()][i])
             {
                 b=1;
                 break;
             }
         }
         if(!b)                       //如果改点没有连边
         {
             printf("%d ",t.top());  //输出该点     输出路径
             t.pop();
         }
         else                //否则 对这点进行深搜
         {
             int y=t.top();
             t.pop();
             dfs(y);
         }
     }
     printf("\n");
  }

使用前向星求路径的解法

int ans[max_m];
int ansi=0;  //for counting
bool visit[2*max_m];    //"2*" means undirected graph
void dfs(int now)
{
    for(int k=edge[now][i];k!=0;k=edge[k].next)
    {
        if(!vis[k])
        {
            vis[k]=true;         //sign the edge
            vis[k^1]=true;       //sign the reverse edge
            dfs(edge[k].to);
            ans[cnt++]=k;
        }
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值