zoukankan      html  css  js  c++  java
  • bzoj2095: [Poi2010]Bridges(二分+混合图求欧拉回路)

    传送门

    这篇题解讲的真吼->这里

    首先我们可以二分一个答案,然后把所有权值小于这个答案的都加入图中

    那么问题就转化为一张混合图(既有有向边又有无向边)中是否存在欧拉回路

    首先

           无向图存在欧拉回路,当且仅当图的所有顶点度数都为偶数且图连通。

           有向图存在欧拉回路,当且仅当图的所有顶点入度等于出度且图连通。

    那么我们怎么判断混合图的欧拉回路是否存在呢?

    我们把无向边的边随便定向,然后计算每一个点的入度和出度。如果有某一个点的入度和出度之差是奇数,那么肯定不存在欧拉回路。

    因为欧拉回路要求入度等于出度,也就是总度数为偶数,所以有奇数度点肯定不存在欧拉回路

    那么现在每个点的入度和出度之差都是偶数,我们把它除以二,设为$x$,那么,对于每一个点,我们只要改变与它相连的$x$条边的方向改变,它就能保证入度等于出度。如果每个点都能这样,那么这张图就存在一个欧拉回路

    那么我们该改变哪些边来让点的出度等于入度呢?首先,有向边不能改变,忽略。然后我们一开始不是把无向边定向了么?那我们就按照定的向构建网络,边长容量$1$。然后新建源点和汇点,如果入度大于出度,则将点向汇点连边,容量为$x$,如果出度大于入度,则将源点向该点连边,容量为$x$。然后我们只要跑一个最大流,看看能否使网络满流。若可以,则有解,否则无解

    考虑为什么。我们把网络中每一条满流的边(也就是流量非0的边)反向,就能得到一个每点入度等于出度的欧拉图。因为这个网络满流,所以每一个入度大于出度的点都会有$x$条边进来,把这$x$条边反向就能使它入度等于出度。出度大于入度的点同理。那么,既没和源点连也没和汇点连的点怎么办呢?因为这样的点必定是入度等于出度的,那么在网络流过程中他们属于中间点,那么必定满足流量守恒,所以进来的流量和出去的流量是一样的,那么反向之后仍然保持平衡

    解决了

      1 //minamoto
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<queue>
      7 #define inf 0x3f3f3f3f
      8 using namespace std;
      9 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     10 char buf[1<<21],*p1=buf,*p2=buf;
     11 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
     12 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
     13 inline int read(){
     14     #define num ch-'0'
     15     char ch;bool flag=0;int res;
     16     while(!isdigit(ch=getc()))
     17     (ch=='-')&&(flag=true);
     18     for(res=num;isdigit(ch=getc());res=res*10+num);
     19     (flag)&&(res=-res);
     20     #undef num
     21     return res;
     22 }
     23 const int N=5005,M=100005;
     24 int head[N],Next[M],ver[M],edge[M],tot;
     25 int out[N],in[N],u[N],v[N],w1[N],w2[N],sum;
     26 int dep[N],cur[N];
     27 int n,m,s,t;
     28 queue<int> q;
     29 inline void add(int u,int v,int e){
     30     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
     31     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0;
     32 }
     33 bool bfs(){
     34     memset(dep,-1,sizeof(dep));
     35     while(!q.empty()) q.pop();
     36     for(int i=s;i<=t;++i) cur[i]=head[i];
     37     q.push(s),dep[s]=0;
     38     while(!q.empty()){
     39         int u=q.front();q.pop();
     40         for(int i=head[u];i;i=Next[i]){
     41             int v=ver[i];
     42             if(dep[v]<0&&edge[i]){
     43                 dep[v]=dep[u]+1,q.push(v);
     44                 if(v==t) return true;
     45             }
     46         }
     47     }
     48     return false;
     49 }
     50 int dfs(int u,int limit){
     51     if(u==t||!limit) return limit;
     52     int flow=0,f;
     53     for(int i=cur[u];i;i=Next[i]){
     54         int v=ver[i];cur[u]=i;
     55         if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){
     56             flow+=f,limit-=f;
     57             edge[i]-=f,edge[i^1]+=f;
     58             if(!limit) break;
     59         }
     60     }
     61     if(!flow) dep[u]=-1;
     62     return flow;
     63 }
     64 int dinic(){
     65     int flow=0;
     66     while(bfs()) flow+=dfs(s,inf);
     67     return flow;
     68 }
     69 bool check(int mid){
     70     memset(head,0,sizeof(head)),tot=1;
     71     memset(out,0,sizeof(out));
     72     memset(in,0,sizeof(in));
     73     sum=0;
     74     for(int i=1;i<=m;++i){
     75         if(w1[i]<=mid) ++out[u[i]],++in[v[i]];//有向边记入度和出度 
     76         if(w2[i]<=mid) add(u[i],v[i],1);//无向边随便定个方向 
     77     }
     78     for(int i=1;i<=n;++i) if(abs(in[i]-out[i])&1) return false;
     79     for(int i=1;i<=n;++i){
     80         int x=in[i]-out[i];
     81         sum+=x>0?x>>1:0;
     82         if(x>0) add(i,t,x>>1);
     83         if(x<0) add(s,i,(-x)>>1);
     84     }
     85     return dinic()==sum;
     86 }
     87 int main(){
     88     //freopen("testdata.in","r",stdin);
     89     n=read(),m=read(),s=0,t=n+1;
     90     int l=inf,r=-inf;
     91     for(int i=1;i<=m;++i){
     92         u[i]=read(),v[i]=read(),w1[i]=read(),w2[i]=read();
     93         if(w1[i]>w2[i]) swap(u[i],v[i]),swap(w1[i],w2[i]);
     94         cmin(l,w1[i]),cmax(r,w2[i]);
     95     }
     96     while(l<=r){
     97         int mid=l+r>>1;
     98         if(check(mid)) r=mid-1;else l=mid+1;
     99     }
    100     if(!check(l)) puts("NIE");else printf("%d
    ",l);
    101     return 0;
    102 }
    103 ?
  • 相关阅读:
    Unable to lock the administration directory (/var/lib/dpkg/)解决办法
    Linux实训——搭建动态网站
    Linux实训——搭建HTTP服务器
    小程序学习视频教程
    数组的所有方法
    小程序组件封装步骤
    微信小程序生成图片学习
    小程序组件封装学习地址
    开发者在 onPageNotFound 回调中进行重定向处理onPageNotFound(Object)
    小程序中view的自定义属性获取
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9564911.html
Copyright © 2011-2022 走看看