• 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 }
  • 相关阅读:
    Python 华为云OSS建桶与文件上传下载删除及检索示例
    Sonar 扫描之分析参数介绍
    浅谈探寻企业数字化
    关于碳中和的一点浅谈
    ElementUI 多选+远程搜索
    vue组件之间共享数据
    vue 音频组件
    vue 视频播放
    在 windows环境下 python 调试信息 输出彩色的字
    MySQL CPU使用彪高,如何快速找到源头
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10639761.html
Copyright © 2020-2023  润新知