#117. 欧拉回路
有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。
一共两个子任务:
- 这张图是无向图。(50分)
输入格式
第一行一个整数 t,表示子任务编号。t∈{1,2},如果 t=1则表示处理无向图的情况,如果 t=2 则表示处理有向图的情况。
第二行两个整数 n,m,表示图的结点数和边数。
接下来 m 行中,第 i 行两个整数 vi,ui,表示第 ii 条边(从 11 开始编号)。保证 1≤vi,ui≤n
图中可能有重边也可能有自环。
- 如果 t=1
- 则表示 vi 到 ui 有一条无向边。
- 如果 t=2
- 则表示 vi 到 ui 有一条有向边。
输出格式
如果不可以一笔画,输出一行 “NO”。
否则,输出一行 “YES”,接下来一行输出一组方案。
如果 t=1,输出 m个整数 p1,p2,…,pm。令 e=∣pi∣,那么 e 表示经过的第 i 条边的编号。如果 pi 为正数表示从 ve 走到 ue,否则表示从 ue 走到 ve。
如果 t=2,输出 m 个整数 p1,p2,…,pm。其中 pi 表示经过的第 i条边的编号。
样例一
input
1 3 3 1 2 2 3 1 3
output
YES 1 2 -3
样例二
2 5 6 2 3 2 5 3 4 1 2 4 2 5 1
YES 4 1 3 5 2 6
限制与约定
1≤n≤10^5,0≤m≤2×10^5
时间限制:1s
空间限制:256MB
【分析】
这是欧拉回路的模板题。
主要是这样:
无向图:所有点的度数都为偶数,一定有欧拉回路,从任意一个点开始都可以。
有向图:所有点的入度=出度,一定有欧拉回路,从任意一个点开始都可以。
我们不断走边,边没打过标记的就走,经过一条边就打标记,表示不能走这条边了,然后回溯的时候把路径记录下来,反着输出就可以。
走过的边不仅要打标记(主要是无向图的反向边要标记一下),还要删除,不然即使不再走这条边也会不断询问它而导致TLE,
解决方法是改变边目录的first数组,表示前面访问过的边都不用再继续访问了。
void ffind(int x)
{
vis[x]=1;
for(int i=first[x];i;i=first[x]) if(t[i].p)
{
int y=t[i].y;
t[i].p=t[t[i].o].p=0;
first[x]=t[i].next;
ffind(y);
op[++op[0]]=t[i].id;
}
else first[x]=t[i].next;
}
核心代码如上。
【GDXB当初告诉我这叫套圈算法?
【主要是回溯那里还有删边那里要记得。

1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<algorithm>
6 #include<queue>
7 #include<stack>
8 using namespace std;
9 #define Maxm 200010
10 #define Maxn 100010
11
12 struct node
13 {
14 int x,y,c,next,o;
15 int id;
16 bool p;
17 }t[2*Maxm];
18 int first[Maxn],len;
19 int T;
20
21 void ins(int x,int y,int id)
22 {
23 t[++len].x=x;t[len].y=y;t[len].p=1;
24 t[len].id=id;t[len].next=first[x];first[x]=len;
25 if(T==1) t[len].o=len&1?len+1:len-1;
26 else t[len].o=len;
27 }
28
29 int rd[Maxn],cd[Maxn],op[Maxm];
30 bool nw=0,vis[Maxn];
31
32 void ffind(int x)
33 {
34 vis[x]=1;
35 for(int i=first[x];i;i=first[x]) if(t[i].p)
36 {
37 int y=t[i].y;
38 t[i].p=t[t[i].o].p=0;
39 first[x]=t[i].next;
40 ffind(y);
41 op[++op[0]]=t[i].id;
42 }
43 else first[x]=t[i].next;
44 }
45
46 int main()
47 {
48 scanf("%d",&T);
49 int n,m;
50 scanf("%d%d",&n,&m);
51 len=0;
52 memset(first,0,sizeof(first));
53 memset(rd,0,sizeof(rd));
54 memset(cd,0,sizeof(cd));
55 for(int i=1;i<=m;i++)
56 {
57 int x,y;
58 scanf("%d%d",&x,&y);
59 rd[y]++;cd[x]++;
60 ins(x,y,i);
61 if(T==1) ins(y,x,-i);
62 }
63 bool ok=1;
64 for(int i=1;i<=n;i++) if(T==1&&(rd[i]+cd[i])%2!=0) {ok=0;break;}
65 for(int i=1;i<=n;i++) if(T==2&&rd[i]!=cd[i]) {ok=0;break;}
66 op[0]=0;
67 if(!ok) printf("NO\n");
68 else
69 {
70 for(int i=1;i<=n;i++) vis[i]=0;
71 for(int i=1;i<=n;i++)
72 {
73 ffind(i);
74 if(op[0]!=0) break;
75 }
76 if(T==1&&op[0]!=len/2) printf("NO\n");
77 else if(T==2&&op[0]!=len) printf("NO\n");
78 else
79 {
80 printf("YES\n");
81 for(int i=op[0];i>=1;i--)
82 {
83 printf("%d ",op[i]);
84 }
85 printf("\n");
86 }
87
88 }
89 return 0;
90 }
View Code