【UOJ 117】欧拉回路
#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 3output
YES 1 2 -3样例二
input
2 5 6 2 3 2 5 3 4 1 2 4 2 5 1output
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 }
2017-03-02 21:09:04