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