题目大意:给你一张可能有重边的不保证联通的无向图,现在要在这个图上找出两条路径,恰好能覆盖所有边一次,根据边的编号输出方案,无解输出-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\n",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\n",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\n",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\n",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\n",m+1-tp);
121 for(i=m+1;i>tp;i--) printf("%d ",stk[i]);
122 puts("");
123 tp--; printf("%d\n",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 }
来源:oschina
链接:https://my.oschina.net/u/4399002/blog/3589863