• CF36E Two Paths (欧拉回路+构造)


    题面传送门

    题目大意:给你一张可能有重边的不保证联通的无向图,现在要在这个图上找出两条路径,恰好能覆盖所有边一次,根据边的编号输出方案,无解输出-1

    一道很不错的欧拉路径变形题

    首先要知道关于欧拉路径的一种算法:Hierholzer算法

    这位神犇的讲解非常不错

    欧拉路径与欧拉回路

    我们称度为奇数的点为奇点,度为偶数的点为偶点

    从一个点开始走,把其它所有边都走了一遍,叫欧拉路径

    从一个点开始走,把其它所有边都走了一遍又回到了这个点,叫欧拉回路

    如果图中存在欧拉回路,所有点均为偶点,画画图就明白了

    如果图中不存在或仅存在两个奇点,那么这个图存在欧拉路径,且路径的起点终点一定分别是这两个奇点。把起点终点连起来不就变成欧拉回路了么

    欧拉回路一定是欧拉路径

    Hierholzer算法

    从图中的一个奇点开始dfs,每遍历到一条边,就在图中删去这条边(包括反向边),然后递归指向的节点

    直到当前节点相连的所有边都被删掉之后,把当前节点推入一个栈中,回溯

    如果原图存在欧拉回路,就能搜出欧拉回路。如果存在欧拉路径,就会搜出欧拉路径。

    栈中存储的是路径的倒序点序列,而边序列就是每次递归前删掉的边构成的序列

    实现比较简单

    那这道题该怎么搞呢?

    (1)如果图中有>2个连通块,一定无解

    (2)如果只有1个连通块,分为0个奇点,2个奇点,4个奇点讨论,其它情况都是无解

    0个奇点就是欧拉回路,断开其中任意一条边,把路径拆成两条就是答案

    2个奇点就是欧拉路径,断开其中任意一条边,把路径拆成两条就是答案

    4个奇点的话,挑两个奇点连起来,再跑欧拉路径就行啦

    (3)如果有2个连通块,说明这两条路径分别在这两个连通块里

    对于每个连通块而言,只能存在0个奇点和2个奇点两种情况,讨论一下就好啦

    代码写得好丑啊TvT

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #define ll long long
      5 #define N1 20010 
      6 using namespace std;
      7 
      8 template <typename _T> void read(_T &ret)
      9 {
     10     ret=0; _T fh=1; char c=getchar();
     11     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     12     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     13     ret=ret*fh;
     14 }
     15 
     16 struct Edge{
     17 int to[N1*2],nxt[N1*2],del[N1*2],head[N1],cte;
     18 void ae(int u,int v)
     19 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
     20 }e;
     21 
     22 int n,m,num;
     23 int inc[N1],vis[N1],use[N1],stk[N1],tp;
     24 void dfs1(int x,int id)
     25 {
     26     int j,v; vis[x]=id; num++;
     27     for(j=e.head[x];j;j=e.nxt[j])
     28     {
     29         v=e.to[j];
     30         if(!vis[v]) dfs1(v,id);
     31     } 
     32 }
     33 void euler(int x)
     34 {
     35     int j,v,la=0;
     36     for(j=e.head[x];j;j=e.nxt[j])
     37     {
     38         if(e.del[j]) continue;
     39         v=e.to[j]; e.del[j]=1; e.del[j^1]=1;
     40         euler(v); stk[++tp]=j>>1; 
     41     } 
     42 }
     43 void fkdown(){ puts("-1"); exit(0); }
     44 int odd[N1],cnt_odd;
     45 
     46 void solve0(int id,int esum)
     47 {
     48     int i;
     49     for(i=1;i<=n;i++) if(vis[i]==id) 
     50     {
     51         euler(i); 
     52         if(tp<esum) fkdown();
     53         printf("%d
    ",tp);
     54         while(tp) printf("%d ",stk[tp--]);
     55         puts(""); 
     56         break;
     57     }
     58 }
     59 void solve2(int id,int esum)
     60 {
     61     euler(odd[1]);
     62     if(tp<esum) fkdown(); // 
     63     printf("%d
    ",tp);
     64     while(tp) printf("%d ",stk[tp--]);
     65     puts(""); 
     66 }
     67 
     68 int main()
     69 {
     70     freopen("input.txt","r",stdin); 
     71     freopen("output.txt","w",stdout);
     72     scanf("%d",&m);
     73     int i,j,x,y,cnt_compo=0; n=10000; e.cte=1;
     74     if(m==1) fkdown(); 
     75     for(i=1;i<=m;i++) 
     76     {
     77         read(x), read(y), e.ae(x,y), e.ae(y,x);
     78         inc[x]++, inc[y]++, use[x]=1, use[y]=1;
     79     }
     80     for(i=1;i<=n;i++) if(use[i] && !vis[i]) cnt_compo++, dfs1(i,cnt_compo);
     81     if(cnt_compo>2) fkdown();
     82     if(cnt_compo==1){
     83         for(i=1;i<=n;i++) if(inc[i]&1) odd[++cnt_odd]=i;
     84         if(!cnt_odd){
     85         
     86         for(i=1;i<=n;i++) if(inc[i]) 
     87         {
     88             euler(i); 
     89             if(tp<m) fkdown();
     90             printf("%d
    ",tp-1);
     91             while(tp>1) printf("%d ",stk[tp--]);
     92             puts(""); 
     93             puts("1");
     94             while(tp>0) printf("%d ",stk[tp--]);
     95             puts(""); 
     96             break;
     97         }
     98         
     99         }else if(cnt_odd==2){
    100         
    101         euler(odd[1]);
    102         if(tp<m) fkdown(); 
    103         printf("%d
    ",tp-1);
    104         while(tp>1) printf("%d ",stk[tp--]);
    105         puts(""); 
    106         puts("1");
    107         while(tp>0) printf("%d ",stk[tp--]);
    108         puts(""); 
    109         
    110         }else if(cnt_odd==4){
    111         
    112         e.ae(odd[2],odd[3]); e.ae(odd[3],odd[2]);
    113         euler(odd[1]);
    114         if(tp-1<m) fkdown(); 
    115         while(tp) 
    116         {
    117             if(stk[tp]>m) break; 
    118             tp--;
    119         }
    120         printf("%d
    ",m+1-tp);
    121         for(i=m+1;i>tp;i--) printf("%d ",stk[i]);
    122         puts(""); 
    123         tp--; printf("%d
    ",tp);
    124         while(tp) printf("%d ",stk[tp--]);
    125         puts(""); 
    126             
    127         }else fkdown();
    128     }else{
    129         int esum=0;
    130         
    131         cnt_odd=0; esum=0;
    132         for(i=1;i<=n;i++) 
    133         {
    134             if(!vis[i] || vis[i]==1) continue; 
    135             if((inc[i]&1)) odd[++cnt_odd]=i;
    136             esum+=inc[i];
    137         }
    138         if(cnt_odd>2 || cnt_odd&1) fkdown();
    139         
    140         cnt_odd=0; esum=0;
    141         for(i=1;i<=n;i++) 
    142         {
    143             if(!vis[i] || vis[i]==2) continue; 
    144             if((inc[i]&1)) odd[++cnt_odd]=i;
    145             esum+=inc[i];
    146         }
    147         if(cnt_odd>2 || cnt_odd&1) fkdown();
    148         esum>>=1;
    149         if(!cnt_odd) solve0(1,esum);
    150         else if(cnt_odd==2) solve2(1,esum);
    151         else fkdown();
    152         
    153         cnt_odd=0; esum=0;
    154         for(i=1;i<=n;i++) 
    155         {
    156             if(!vis[i] || vis[i]==1) continue; 
    157             if((inc[i]&1)) odd[++cnt_odd]=i;
    158             esum+=inc[i];
    159         }
    160         esum>>=1;
    161         if(!cnt_odd) solve0(2,esum);
    162         else if(cnt_odd==2) solve2(2,esum);
    163         else fkdown();
    164     }
    165     return 0;
    166 }
  • 相关阅读:
    Balanced Binary Tree
    Convert Sorted List to Binary Search Tree
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Validate Binary Search Tree
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Maximum Depth of Binary Tree
    如何把U盘的两个盘或者多个盘合成一个
    bugku 想蹭网先解开密码
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10639761.html
Copyright © 2020-2023  润新知