• 哈密顿+欧拉图


    Euler回路:图G的一个回路,恰通过G中每条边一次。

    A. 连通图

    B. 对于无向图,度数为奇数的点的个数为0。

    C. 对于有向图,每个顶点的入度等于出度。

    Euler通路:一笔画问题

    B’.对于无向图,度数为奇数的个数为2。

    c’.对于有向图,存在2个顶点,其入度不等于出度,其中起点的出度比入度大1,终点的入度比出度大1。

     

    O(m):无向图+链式前向星+DFS

     1 //欧拉回路
     2 const int MAXN = 111111;
     3 int ans[MAXN];//记录边的路径
     4 int ansi = 0;
     5 bool visit[2*MAXN];
     6 void DFS(int now)
     7 {
     8     int k ;
     9     for(k = first[now]; k != -1; k = edge[k].next)
    10     {
    11         if(!visit[k])
    12         {
    13             visit[k] = true;
    14             visit[k^1] = true;//标记反向边
    15             DFS( edge[k].to);
    16             ans[ansi++] = k;
    17         }
    18     }
    19 }
    Euler 回路

    如要记录点的路径,在整层DFS结束之前,保存当前点的序号now。

     



     

    Hamilton回路:图G的一个回路,通过G中每个点一次且仅一次。

    G为具有n个顶点的无向图。

    A. 充分条件:

    G中任意两个不同顶点的度数之和大于等于n。

    B. 必要条件:

    删除任意的一个非空子集S,G-S的连通分支数要不大于原图S的连通分支数。

     

    哈密顿回路构造:

    前提:充分条件A。

    O(n^2):无向图+邻接矩阵(边多)+ reserve函数

      1 //哈密顿回路
      2 inline void reserve(int ans[MAXN],int s,int t)
      3 {
      4     int temp;
      5     while(s < t)
      6     {
      7         temp = ans[s];
      8         ans[s] = ans[t];
      9         ans[t] = temp;
     10         s ++ ;
     11         t -- ;
     12     }
     13 }
     14 void Hamilton(int ans[MAXN],bool map[MAXN][MAXN],int n)
     15 {
     16     int s = 1,t;
     17     int ansi = 2;
     18     int i,j;
     19     int w;
     20     int temp;
     21     bool visit[MAXN] = {false};
     22     for(i = 1;i<n;i++) if(map[s][i])break;//任取邻接s的点为t
     23     t = i;
     24     vist[s] = visit[t] = true;
     25     ans[0] = s;
     26     ans[1] = t;
     27 
     28     while(true)
     29     {
     30         //从1点向外扩展
     31         while(true)
     32         {
     33             for( i = 1;i<n;i++)
     34             {
     35                 if(map[t][i] && !visit[i])
     36                 {
     37                     ans[ansi++] = i;
     38                     visit[i] = true;
     39                     t = i;
     40                     break;
     41                 }
     42             }
     43             if(i > n)break;//无结点可扩展
     44         }
     45 
     46         /*
     47         将当前得到的序列倒置,s与t互换,从t继续扩展,
     48         相当于在原来的序列上从s向外扩展。
     49         */
     50         w = ansi - 1;
     51         i = 0;
     52         reserve(ans, i ,w);
     53         temp = s;
     54         s = t;
     55         t = temp;
     56         //从新的t继续扩展,相当于在原来的序列上从s向外扩展。
     57         while(true)
     58         {
     59             for( i = 1;i<n;i++)
     60             {
     61                 if(map[t][i] && !visit[i])
     62                 {
     63                     ans[ansi++] = i;
     64                     visit[i] = true;
     65                     t = i;
     66                     break;
     67                 }
     68             }
     69             if(i > n)break;//无结点可扩展
     70         }
     71 
     72         //如果s与t不相邻,进行调整
     73         if(!map[s][t])
     74         {
     75             /*
     76             取序列中一个点i,使得ans[i]与t相连,ans[i+1]与s相连
     77             */
     78             for(i = 1;i<ansi - 2 ;i++)
     79                 if(map[ans[i]][t]&&map[s][ans[i+1]])break;
     80             w = ansi - 1;
     81             i ++;
     82             t = ans[i];
     83             reserve(ans, i, w);
     84         }
     85 
     86         //如果当前s与t相连
     87         if(ansi == n)return ;
     88         /*
     89             当前序列中元素个数小于n,
     90             寻找点ans[i],使得ans[i]与ans[]外的一点相连
     91         */
     92         for(j = 1;j<n;j++)
     93         {
     94             if(visit[j]) continue;
     95             for(i = 1;i<ansi - 2;i++)
     96                 if(map[ans[i]][j])break;
     97             if(map[ans[i]][j])break;
     98         }
     99         s = ans[i-1];
    100         t = j;
    101         //将ans[]中s到ans[i-1]部分的ans[]倒置
    102         reserve(ans,0,i-1);
    103         //将ans[]中ans[i]到t部分的ans[]倒置
    104         reserve(ans,i,ansi - 1);
    105         //将点j加入ans[]的尾部
    106         ans[ansi++] = j;
    107         visit[j] = true;
    108     }
    109 }
    Hamilton 回路

     

    思路的分析和证明就略去了,详细参见<图论及应用> 冯林 金博 于瑞云

    模板有待测试,之后找些题目试试。然后再贴。

    为什么这样是对的? 为什么那样是错的? 凭什么这样是最优的? 凭什么那样不是最优的? 为什么没有更优的解法? 就不能找一个更好的解法吗? 若不知其所以然何苦知其然?
  • 相关阅读:
    设计模式概述
    Android之.9.png图片的制作与使用
    2015-4-3~2015-5-28 第四届全国大学生软件设计大赛《解密陌生人》项目总结
    排序算法之快速排序
    AsyncTask那些事(更新中...)
    经典Android面试题
    import第三方库的头文件找不到的错误
    点击某个按钮在tableView某个位置动态插入一行cell
    NSUserDefaults:熟悉与陌生(转)
    更改UIsearchbar 的背景和cancel按钮(转)
  • 原文地址:https://www.cnblogs.com/PeanutPrince/p/3468480.html
Copyright © 2020-2023  润新知