UOJ 117欧拉回路

Posted konjak魔芋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UOJ 117欧拉回路相关的知识,希望对你有一定的参考价值。

#117. 欧拉回路

有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。

一共两个子任务:

  1. 这张图是无向图。(50分)

输入格式

第一行一个整数 t,表示子任务编号。t{1,2},如果 t=1则表示处理无向图的情况,如果 t=2 则表示处理有向图的情况。

第二行两个整数 n,m,表示图的结点数和边数。

接下来 m 行中,第 i 行两个整数 vi,ui,表示第 ii 条边(从 11 开始编号)。保证 1vi,uin

  1. 如果 t=1 
  2. 则表示 vi 到 ui 有一条无向边。
  3. 如果 t=2 
  4. 则表示 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

样例二

input

2
5 6
2 3
2 5
3 4
1 2
4 2
5 1

output

YES
4 1 3 5 2 6

限制与约定

1n10^5,0m2×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

 

2017-03-02 21:09:04

以上是关于UOJ 117欧拉回路的主要内容,如果未能解决你的问题,请参考以下文章

算法复习——欧拉回路(uoj117)

uoj117:欧拉回路——题解

UOJ117. 欧拉回路

UOJ 117欧拉回路

UOJ 117 欧拉回路

UOJ.117.欧拉回路