题目链接: 传送门
题意:
给定一个无向图,让你给每个边加上方向使得每个点的|入度-出度|的绝对值小于等于1.
思路:
对于一个顶点我们每次寻找与他相连的一条链,如果当前个点的入度小于出度则我们将这条链的
方向设为使入度增加的放向。相反则设为使出度增加的放向。写的时候遍历过的边就不要再走了
因此需要删边。
Ps.比赛的时候YY感觉不可能有-1的情况但是没法证明,具体的证明请看:传送门
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 1e5+10;
int head[maxn],in[maxn],out[maxn],tot[maxn];
bool vis[maxn*6];
struct nod {
int to,next;
} edge[6*maxn];
int n,m,ip;
int ans[maxn*6];
void init(){
ip=0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(tot,0,sizeof(tot));
}
void add(int u,int v) {
edge[ip].to = v ;
edge[ip].next = head[u] ;
head[u] = ip++ ;
}
void dfs_in(int u) {
for(int i=head[u]; i!=-1; i=edge[i].next) {
if(vis[i]) {
head[u]=edge[i].next;
continue;
}
int v=edge[i].to;
if(u!=v && out[v]>in[v]) continue;
vis[i]=1,vis[i^1]=1; //标记,删边
head[u] = edge[i].next;
in[u]++,out[v]++;
if(i%2) ans[i/2] = 1;
else ans[i/2] = 0;
dfs_in(v);
return;
}
}
void dfs_out(int u) {
for(int i=head[u]; i!=-1; i=edge[i].next) {
if(vis[i]) {
head[u]=edge[i].next;
continue;
}
int v=edge[i].to;
if(u!=v && in[v]>out[v]) continue;
vis[i]=1,vis[i^1]=1; //标记,删边
head[u] = edge[i].next;
in[v]++,out[u]++;
if(i%2) ans[i/2] = 0;
else ans[i/2] = 1;
dfs_out(v);
return ;
}
}
int main() {
int t;
scanf("%d",&t);
while(t--) {
init();
scanf("%d%d",&n,&m);
for(int i=0; i<m; i++) {
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
tot[u]++,tot[v]++;
}
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; i++) {
while(out[i]+in[i]<tot[i]) {
if(out[i]>in[i]) dfs_in(i);
else dfs_out(i);
}
}
for(int i=0;i<m;i++)
printf("%d\n",ans[i]);
}
return 0;
}