51Nod 1967 路径定向

原题

给出一个有向图,要求给每条边重定向,使得定向后出度等于入度的点最多,输出答案和任意一种方案。

解题思路

考虑入度与出度之和的奇偶性。
如果是奇数,那么显然不行。
如果是偶数,那么可以构造出一种方案,使得入度与出度之和为偶数的点,入度与出度相等。
因此答案就出来了。
关键是答案咋求。
有一个性质,就是如果一个无向图存在欧拉回路(也就是一条路径经过所有的边,且不重复),那么这个无向图中的所有点的入度与出度之和一定为偶数。
在无向图中,奇点一定有偶数个。
所以让奇点两两连边,这个无向图就是存在欧拉回路的了。
然后暴走一遍就行了。
但是卡常卡死人。考虑数组的寻址时间,我将结构体拆了,快了一点点。
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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值