2 3 3 1 2 2 3 3 1 7 6 1 2 1 3 1 4 1 5 1 6 1 7
1 1 1 0 1 0 1 0 1
题意:一个具有n个结点,m条无向边的无向图,要求我们规定每条边的方向,使其成为有向图之后每个结点的入度与出度差的绝对值小于1,若无解,则输出-1
解题思路:该题的解法有很多种,有用欧拉路的,也有用搜索的,而我要讲的方法就是深搜
首先我们先看看多校题解报告中的思路
下面给出我做此题时的思路
首先暂且先不考虑环还是树,直接进行深搜,对每个点进行出度和入度的判断,如果出度大,就先进行反向的搜索(每搜索一条边u,v就认为这是一条从v到u的有向边),如果入度大,进行正向搜索(每搜到一条边u,v认为这是一条从u到v的有向边),一直搜索到找不到边能继续为止。
注意:
①已经使用过的边为了防止再次被遍历到,可以修改head[u]的值,即head[u] = edge[i].next
②注意自环,因为能否继续向下层搜索是根据v的入度和出度大小来决定的,但是如果是自环的话可能会影响继续搜索。
另外,此题不存在无解的可能
反证法证明:假设存在一个结点v,满足该结点的入度比出度多2,那么,当有一条边搜索到v后找不到后继,导致v的入度比出度多1,这时又有一条边搜索到v,导致v的入度比出度多2,但是这样的话就会与第一条找不到后继的情况冲突,所以不会出现入度比出度多2的情况,其余情况亦是如此,所以不会有无解的结果。
闲话不多说,上AC代码
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<math.h> #include<vector> #include<map> #include<set> #include<cmath> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 using namespace std; const int N = 100005; const int inf = 1000000000; struct node { int to,next; }edge[6*N]; int k,head[N],num[N],in[N],out[N],n,ans[N*3]; bool vis[N*6]; void add_edge(int from,int to) { edge[k].to=to; edge[k].next=head[from]; head[from]=k++; } void DFS1(int u) { int i,v; for(i=head[u];i+1;i=edge[i].next) { if(vis[i]) { head[u]=edge[i].next; continue; } v=edge[i].to; if(u!=v&&in[v]>out[v]) continue; out[u]++; in[v]++; vis[i]=vis[i^1]=true; ans[i/2]=i%2?0:1; head[u]=edge[i].next; DFS1(v); break; } } void DFS2(int u) { int i,v; for(i=head[u];i+1;i=edge[i].next) { if(vis[i]) { head[u]=edge[i].next; continue; } v=edge[i].to; if(u!=v&&in[v]<out[v]) continue; out[v]++; in[u]++; vis[i]=vis[i^1]=true; ans[i/2]=i%2?1:0; head[u]=edge[i].next; DFS2(v); break; } } int main() { int t,m,i,u,v; scanf("%d",&t); while(t--) { k=0; memset(head,-1,sizeof(head)); memset(num,0,sizeof(num)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(vis,false,sizeof(vis)); scanf("%d%d",&n,&m); for(i=0;i<m;i++) { scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); num[u]++; num[v]++; } for(i=1;i<=n;i++) while(in[i]+out[i]<num[i]) if(in[i]>=out[i]) DFS1(i); else DFS2(i); for(i=0;i<m;i++) printf("%d\n",ans[i]); } return 0; }