原题
给出一个有向图,要求给每条边重定向,使得定向后出度等于入度的点最多,输出答案和任意一种方案。
解题思路
考虑入度与出度之和的奇偶性。
如果是奇数,那么显然不行。
如果是偶数,那么可以构造出一种方案,使得入度与出度之和为偶数的点,入度与出度相等。
因此答案就出来了。
关键是答案咋求。
有一个性质,就是如果一个无向图存在欧拉回路(也就是一条路径经过所有的边,且不重复),那么这个无向图中的所有点的入度与出度之和一定为偶数。
在无向图中,奇点一定有偶数个。
所以让奇点两两连边,这个无向图就是存在欧拉回路的了。
然后暴走一遍就行了。
但是卡常卡死人。考虑数组的寻址时间,我将结构体拆了,快了一点点。
putchar都要用问号语句。
用vector存边,快了一匹。但是要注意一个细节。
有很多的人在define的时候将for(i=a;i<=b;i++)变成fo(i,a,b)。
但是,在这条语句中绝对不允许这样做。
for(i=0;i
<
<
<script type="math/tex" id="MathJax-Element-24"><</script>a[x].size();i++)绝对不能够改为fo(i,0,a[i].size()-1)
因为
a[i].size()
a
[
i
]
.
s
i
z
e
(
)
会变。骚操作。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define N 100003
#define M 300003
#define N1 670003
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note{
int st,en;
}edge[N1];
int head[N],tot;
int i,j,k,l,n,m,cnt;
int u,v;
int d[N],ans[350003];
bool bz[N];
vector<int>a[N],b;
int read(){
int fh=1,rs=0;char ch;
while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
return fh*rs;
}
void dg(int x){
register int i;
bz[x]=1;
for(i=0;i<a[x].size();i++){
int j=a[x][i];
if(~ans[j])continue;
if(edge[j].st==x)ans[j]=0,dg(edge[j].en);
else ans[j]=1,dg(edge[j].st);
}
}
int main(){
memset(ans,-1,sizeof(ans));
n=read(),m=read();
tot=1;
fo(i,0,m-1){
edge[i].st=read(),edge[i].en=read();
a[edge[i].st].push_back(i);
a[edge[i].en].push_back(i);
d[edge[i].st]++;d[edge[i].en]++;
}
fo(i,1,n)if(d[i]&1)b.push_back(i),cnt++;
for(i=0;i<b.size();i+=2){
edge[m+(i>>1)].st=b[i];
edge[m+(i>>1)].en=b[i+1];
a[b[i]].push_back(m+(i>>1));
a[b[i+1]].push_back(m+(i>>1));
}
printf("%d\n",n-cnt);
fo(i,1,n)if(!bz[i])dg(i);
fo(i,0,m-1)putchar(ans[i]?'1':'0');
return 0;
}