zoukankan      html  css  js  c++  java
  • POI2010 Bridges

    好题(Qomega Q)

    我们考虑这个东西要求最大值最小,显然一眼二分答案对吧.

    问题在于如何(check),我们二分答案之后把问题转换成了混合图如何求欧拉回路.

    考虑欧拉回路的性质,每一个点的入度要(=)出度.

    但是存在无向边,我们先随便让它选择一个方向,然后连一条反向边,容量为1.

    这样子我们考虑选这样子一条边意味着让一个点的入度与出度的差 减少/增加 2.

    然后直接跑最大流判断是否满流即可.

    /*
      mail: mleautomaton@foxmail.com
      author: MLEAutoMaton
      This Code is made by MLEAutoMaton
    */
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iostream>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    inline int gi(){
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=2010,Inf=1e9+10;
    int n,m,front[N],cnt,dep[N],cur[N],s,t,d[N];queue<int>Q;
    struct node{int to,nxt,w;}e[N*20];
    void Add(int u,int v,int w){
    	e[cnt]=(node){v,front[u],w};front[u]=cnt++;
    	e[cnt]=(node){u,front[v],0};front[v]=cnt++;
    }
    struct edge{int u,v,c,d;}edg[N];
    bool bfs(){
    	Q.push(s);memset(dep,0,sizeof(dep));dep[s]=1;
    	while(!Q.empty()){
    		int u=Q.front();Q.pop();
    		for(int i=front[u];~i;i=e[i].nxt){
    			int v=e[i].to;
    			if(!dep[v] && e[i].w){
    				dep[v]=dep[u]+1;Q.push(v);
    			}
    		}
    	}
    	return dep[t];
    }
    int dfs(int u,int flow){
    	if(u==t || !flow)return flow;
    	for(int &i=cur[u];~i;i=e[i].nxt){
    		int v=e[i].to;
    		if(dep[v]==dep[u]+1 && e[i].w){
    			int di=dfs(v,min(e[i].w,flow));
    			if(di){
    				e[i].w-=di;e[i^1].w+=di;return di;
    			}
    			else dep[v]=0;
    		}
    	}
    	return 0;
    }
    int Dinic(){
    	int flow=0;
    	while(bfs()){
    		for(int i=s;i<=t;i++)cur[i]=front[i];
    		while(int d=dfs(s,Inf))flow+=d;
    	}
    	return flow;
    }
    int build(int mid){
    	memset(front,-1,sizeof(front));cnt=0;
    	memset(d,0,sizeof(d));int tot=0;s=0;t=n+1;
    	for(int i=1;i<=m;i++){
    		int C=edg[i].c,D=edg[i].d;
    		if(C<=mid){d[edg[i].u]--;d[edg[i].v]++;}
    		if(D<=mid)Add(edg[i].v,edg[i].u,1);
    	}
    	for(int i=1;i<=n;i++)
    		if(d[i]&1)return 0;
    	for(int i=1;i<=n;i++)
    		if(d[i]>0)Add(s,i,d[i]/2),tot+=d[i]/2;
    		else Add(i,t,-d[i]/2);
    	return tot+1;
    }
    bool check(int mid){
    	int tot=build(mid);
    	if(!tot)return false;
    	tot--;
    	return Dinic()==tot;
    }
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("in.in","r",stdin);
    #endif
    	n=gi();m=gi();int l=Inf,r=-Inf;
    	for(int i=1;i<=m;i++){
    		edg[i].u=gi(),edg[i].v=gi(),edg[i].c=gi(),edg[i].d=gi();
    		if(edg[i].c>edg[i].d)
    			swap(edg[i].u,edg[i].v),swap(edg[i].c,edg[i].d);
    		l=min(l,edg[i].c);r=max(r,edg[i].d);
    	}
    	int ret=0;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(check(mid)){r=mid-1;ret=mid;}
    		else l=mid+1;
    	}
    	if(ret)printf("%d
    ",ret);
    	else puts("NIE");
    	return 0;
    }
    
  • 相关阅读:
    [bzoj5285][Hnoi2018]寻宝游戏【复杂度分析】
    2020-2021-1 20201229《信息安全专业导论》第十二周学习总结
    2020-2021-1 20201229《信息安全专业导论》第十一周学习总结
    2020-2021-1 20201229《信息安全专业导论》第十周学习总结
    2020-2021-1 20201229 《信息安全专业导论》第九周学习总结
    熟悉编程语言
    2020-2021-1 20201229 《信息安全专业导论》第八周学习总结
    如何学好编程
    2020-2021-1 20201229 《信息安全专业导论》 第七周学习总结
    实现进制转化伪代码
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/11253170.html
Copyright © 2011-2022 走看看