zoukankan      html  css  js  c++  java
  • 一笔画问题

    看标题不知道大家有没有想起小学做的七桥问题

    一笔画问题主要包括欧拉路,欧拉回路,哈密尔顿通路,哈密尔顿回路

    欧拉路

    定义:无向图 G 中一条从 S 到 T 的路径不重不漏地经过了 G 中的每条边,称这条路径为欧拉路

    其实欧拉路就是让你判断能否从一个点到另一个点,每条边只经过一次且经历所有的边的问题,其中对起点终点不做要求,对经过几次相同的点不做要求

         ·    

    比如这两个图就存在欧拉路(可能有多种走法)

    那么怎么判断是否存在欧拉路呢?

    全部的点中只有两个点的度数为奇数,其他点的度数为偶数 ---欧拉

     证明:

    考虑起点,可能会经过多次,但最后一次一定是出去了,但不回来,终点类似

    考虑其他点,都是进来一次出去一次

    程序实现:

    我们把一个度数为奇数的点作为起点,开始dfs,经过一条边删一条边,那么只要有边就会一直dfs下去,如果先遍历到了终点,回溯即可,回溯的时候并把点加入栈里,最后输出整个栈中的元素

    看一个板子题

    Luogu P2731 [USACO3.3]骑马修栅栏 Riding the Fences

    题意还是比较好理解的

    坑点就是有多组解时,输出第一位较小的。就是说在满足解的情况下,前面的数尽可能小

    因为我们使用的是dfs所以先遍历的元素会较晚被放进栈中,所以我们让先遍历的元素尽可能小就好了,如果是欧拉回路,把起点设为1

     1 /*
     2 Work by: Suzt_ilymtics
     3 */
     4 #include<iostream>
     5 #include<cstdio>
     6 using namespace std;
     7 const int MAXN = 501;
     8 int m, wz = 1;
     9 int e[MAXN][MAXN], du[MAXN];
    10 int s[2048], sc = 0;
    11 
    12 void dfs(int u){
    13     for(int i = 1; i <= 500; ++i){
    14         if(e[u][i]){
    15             e[u][i]--, e[i][u]--, dfs(i);
    16         }
    17     }
    18     s[++sc] = u;
    19 }
    20 
    21 int main()
    22 {
    23     scanf("%d", &m);
    24     for(int i = 1, u, v; i <= m; ++i){
    25         scanf("%d%d", &u, &v);
    26         e[u][v]++;e[v][u]++;
    27         du[u]++;du[v]++;
    28     }
    29     int cnt1 = 0, cnt2 = 0;
    30     for(int i = 500; i >= 1; --i){
    31         if(du[i] % 2) cnt1++, wz = i;
    32         else cnt2++;
    33     }
    34     dfs(wz);
    35     while(sc)
    36         printf("%d
    ", s[sc--]);
    37         
    38     return 0;
    39 }
    View Code

    欧拉回路

    定义:无向图 G 中一条从 S 到 S 的路径不重不漏地经过了 G 中的每条边,称这条路为欧拉回路

    含有欧拉路的图叫欧拉图,不含欧拉路的图叫半欧拉图

    同欧拉路的区别就是把终点改成起点而已,其他没什么变化

                 

     比如这就是两个欧拉回路

    怎样的图存在欧拉回路?

    全部点的度数为偶数

     证明:

    起点和终点是同一个点,即出去还要回来,所以为偶,其他点上面已经解释过了

    怎么求?

    和欧拉路一样。。。

    起点随便定,dfs就好

    例题:P1341 无序字母对

    虽然题目中说是字母,但ASCLL码是个好东西,直接强制转整形存即可(就像上面的骑马修栅栏)

    注意处理的几个点:

    1、输出顺序(和修栅栏一样处理)

    2、如果是欧拉回路,第一个点不一定是a

    3、如果既不是欧拉路,也不是欧拉回路那就No Solution

     1 /*
     2 Work by: Suzt_ilymtics
     3 */
     4 #include<iostream>
     5 #include<cstdio>
     6 using namespace std;
     7 const int MAXN = 501;
     8 int m, wz1, wz2;
     9 char uu, vv;
    10 int u, v;
    11 int e[MAXN][MAXN], du[MAXN];
    12 int s[2048], sc = 0;
    13 
    14 void dfs(int u){
    15     for(int i = 1; i <= 500; ++i){
    16         if(e[u][i]){
    17             e[u][i]--, e[i][u]--, dfs(i);
    18         }
    19     }
    20     s[++sc] = u;
    21 }
    22 
    23 int main()
    24 {
    25     scanf("%d", &m);
    26     for(int i = 1; i <= m; ++i){
    27         cin>>uu>>vv;
    28         u = (int) uu;
    29         v = (int) vv;
    30 //        cout<<u<<" "<<v<<endl;
    31         e[u][v]++;e[v][u]++;
    32         du[u]++;du[v]++;
    33     }
    34     int cnt1 = 0, cnt2 = 0;
    35     for(int i = 500; i >= 1; --i){//样例是个环, 所以没有奇数点 
    36         if(du[i] % 2) cnt1++, wz1 = i;
    37         else cnt2++;
    38         if(du[i]) wz2 = i;
    39     }
    40     if(cnt1 == 2) dfs(wz1);
    41     else if(cnt1 == 0) dfs(wz2);
    42     else {
    43         printf("No Solution"); return 0;
    44     }
    45     
    46     while(sc)
    47         printf("%c", (char)s[sc--]);
    48     
    49     return 0;
    50 }
    View Code

    有向图的欧拉(回)路

    上面我们在说的时候都是无向图,那有向图呢?

    怎样的有向图存在欧拉路?

    有两个点,一个点入度比出度多一,另一个点出度比入度多一,其余的点入度等于出度。

    欧拉回路呢?

    所有的点的出度等于入度

    哈密尔顿通路

    定义:无向图 G 中一条从 S 到 T 的路径不重不漏地经过所有的顶点,那么称条路径为哈密尔顿通路。

    解释一下就是从一个点出发到另一个点,每个点只经过一次且每个点都要被经过,对边不做要求

    去掉下图中的一条边就是哈密尔顿通路

    怎么求?

    枚举起点和终点,在这之间加一条边,转化为哈密尔顿回路的问题

    N阶竞赛图:

    含有 N 个顶点的有向图,且每对顶点之间都有一条边。对于 N 阶竞赛图一定存在哈密尔顿通路

    证明:

    N = 2 时显然是成立的。

    设 N = k 时是成立的,考虑证明 N = k + 1 时是成立的,设哈密尔顿路径为$V_1,V_2,…,V_k$

    从k到1去找($V_i,V_k+1$)这样一条边,如果找到了那么形成$V_1,V_2,…V_i,V_k+1,V_i+1…,V_k$,这样一条通路。

    否则形成$V_k+1,V_1,V_2,…,V_k$,这样一条通路

    例题:U132303 竞赛图中的哈密尔顿通路

    显然就是模拟上述过程,可能看代码会更清晰一点

     

     1 /*
     2 Work by: Suzt_ilymics
     3 Knowledge: 竞赛图中的哈密尔顿通路 
     4 Time: 貌似是O(n^3)
     5 */
     6 #include<iostream>
     7 #include<cstdio>
     8 using namespace std;
     9 int n, ans[1010], now; 
    10 bool e[1010][1010];
    11 
    12 void ins(int pos, int k){//暴力插入 
    13     int temp;
    14     now++;
    15     for(int i = pos; i < now; ++i){
    16         temp = ans[i], ans[i] = k, k = temp;
    17     }
    18 }
    19 
    20 void hamillton(){
    21     now = 2; ans[1] = 1;//now表示现在前几个元素构成了hamillton通路 
    22     for(int i = 2; i <= n; ++i){
    23         bool flag = false;
    24         for(int j = now - 1; j >= 1; --j){
    25             if(e[ans[j]][i]){//如果从现有的元素中找到一个指出去的hamillton通路 
    26                 flag = true;
    27                 ins(j+1, i);//就将他插进去 
    28                 break;
    29             }
    30         }
    31         if(!flag) ins(1, i);//如果没找到,就插到最前面 
    32     }
    33 }
    34 
    35 int main()
    36 {
    37     scanf("%d", &n);
    38     for(int i = 1, u, v; i <= (n * (n - 1)) / 2; ++i){
    39         scanf("%d%d", &u, &v);
    40         if(u < v) e[u][v] = 1;//我们只记录指出来的边 
    41     }
    42     hamillton();
    43     for(int i = 1; i <= n; ++i){
    44         printf("%d
    ", ans[i]);
    45     }
    46     return 0;
    47 }
    View Code

     

     

    哈密尔顿回路

    定义:无向图 G 中一条从 S 到 S 的路径不重不漏的的经过除 S 外所有的顶点并且S 只经过了两次,那么称这条路径为哈密尔顿回路。

    解释一下,就是把起点改成终点,其他的同哈密尔顿通路

    还是如下图:

     因为这是一个NPC问题(我也不太懂),所以它没有很好的判定定理,这里只给出一些充分条件和必要条件

    必要条件:

    定理一:

    无向图$G { V , E }$ 哈密尔顿图,V1是V的任意非空子集,都有 P(G , V1) <= | V1 | ,其中 P (G , V1)表示图(G , V1)的联通分量数

    证明:设 G 中地哈密尔顿回路为C,那么P(G,V1) <= P(C-V1)。因为C 是 G 的一个子图,往图中加边不会增加强连通分量的数量。因此只需要证明 P(C - V1) <= |V1|即可

    C是哈密尔顿回路,一定是个环,然后开始删点,在最优的情况下第一次删点使得不再是个环,但是没有增加强联通分量的个数,之后每次删点最多能使得连通分量个数加1,也就是最多有 |V1| 个连通分量,即P(C - V1)<=|V1|。

    注意,必要条件只能判断一个图不是哈密尔顿

    左图满足上述条件,但没有哈密尔顿回路

    推论一:

    无向图G{V,E}中存在哈密尔顿通路,V1是V的任意非空子集,都有 P(G - V1) <= |V1| + 1。

    根据上面的证明这个也很好理解。

    下面这三个图都不存在哈密尔顿通路,第一个删掉5个点后共7个连通分量,第二个删3个共4个,第三个删5个共6个,不满足上述推论,所以一定没有哈密尔顿通路

     充分条件:

    Dirac定理:(狄拉克,1953)

    设 G 是无向简单图, |G| = (n >=3),若 G 中每个节点度数至少为n / 2 ,则 G 有哈密尔顿回路

    Ore定理:(奥尔,1960)

    设 G 是无向简单图,|G| =(n >= 3),若 G 中任意不相邻的两个点 u,v都满足 d(u) + d(v) >= n,则 G 有哈密尔顿回路。

    Ore定理的推论:

    …,|G| >= 2,…d(u) +d(v) >= n -1,则 G 是哈密尔顿图


    最后感谢yu__xuan学姐的课件支持!

  • 相关阅读:
    挺好用的SQLSERVER数据库自动备份工具SQLBackupAndFTP(功能全面)
    SQLSERVER中的鬼影索引
    SQLSERVER NULL和空字符串的区别 使用NULL是否节省空间
    SQLSERVER中NULL位图的作用
    SQLSERVER到底能识别多少个逻辑CPU?
    不正常关机引起的数据库置疑
    如何在大型的并且有表分区的数据库中进行DBCC CHECKDB操作
    索引视图是否物理存储在数据库中以及使用索引视图的一些见解
    Oracle非重要文件恢复,redo、暂时文件、索引文件、password文件
    最大匹配、最小顶点覆盖、最大独立集、最小路径覆盖(转)
  • 原文地址:https://www.cnblogs.com/Silymtics/p/13833618.html
Copyright © 2011-2022 走看看