zoukankan      html  css  js  c++  java
  • P4126-[AHOI2009]最小割【网络流,tarjan】

    正题

    题目链接:https://www.luogu.com.cn/problem/P4126


    题目大意

    给出(n)个点(m)条边的一张有向图和起点终点。对于每条边求其是否是最小割的可行割/必须割

    (1leq nleq 4000,1leq mleq 60000)


    解题思路

    一些结论吧,首先是可行割,跑一次最大流,然后如果一条边是可行割需要满足

    • 该边满流
    • 残量网络上没有(x,y)之间的环

    首先满流是显然的,然后第二个结论的话,如果它们之间有环,那么从(y)顺着环的方向逆流回去的话那么最大流不变但是这条边的流量减少了。

    然后必须割的话也是两个条件

    • 该边满流
    • 残量网络上(s)能到(x)(y)能到(t)

    这个我直接搬之前的证明了

    证明:在残量网络上(s)可以到达(x)(y)可以到达(t)那么说明若该边不割那么(s)就可以通过该边到达(t)。假设在(s)(x)的路上有同样长度的一条道路且割掉后可以使(s)到达(x)那么在残量网络上该边的流量必定为0,因为切割掉(x->y)的流量也必定会经过该边所以在残量网络上(s)就不可以到达(x)了。所以该假设不成立。
    证毕

    所以跑完最大流再跑一次(tarjan)然后按照上面判就好了


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    #include<queue>
    using namespace std;
    const int N=4100,M=6e4+10,inf=1e9;
    struct node{
    	int to,next,w;
    }a[M<<1];
    int n,m,s,t,tot,cnt,num,ls[N],id[M];
    int dep[N],dfn[N],low[N],col[N];
    bool ins[N];
    stack<int> st;queue<int> q;
    void addl(int x,int y,int w){
    	a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
    	a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
    	return;
    }
    bool bfs(){
    	while(!q.empty())q.pop();q.push(s);
    	memset(dep,0,sizeof(dep));dep[s]=1;
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for(int i=ls[x];i;i=a[i].next){
    			int y=a[i].to;
    			if(dep[y]||!a[i].w)continue;
    			dep[y]=dep[x]+1;
    			if(y==t)return 1;
    			q.push(y);
    		}
    	}
    	return 0;
    }
    int dinic(int x,int flow){
    	if(x==t)return flow;
    	int rest=0,k;
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;
    		if(dep[x]+1!=dep[y]||!a[i].w)continue;
    		rest+=(k=dinic(y,min(flow-rest,a[i].w)));
    		a[i].w-=k;a[i^1].w+=k;
    		if(rest==flow)return rest;
    	}
    	if(!rest)dep[x]=0;
    	return rest;
    } 
    void tarjan(int x){
    	dfn[x]=low[x]=++cnt;
    	ins[x]=1;st.push(x);
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;
    		if(!a[i].w)continue;
    		if(!dfn[y]){
    			tarjan(y);
    			low[x]=min(low[x],low[y]);
    		}
    		else if(ins[y])
    			low[x]=min(low[x],dfn[y]);
    	}
    	if(low[x]==dfn[x]){
    		int k;++num;
    		do{
    			k=st.top();st.pop();
    			col[k]=num;ins[k]=0;
    		}while(k!=x);
    	}
    	return;
    }
    signed main()
    {
    	scanf("%d%d%d%d",&n,&m,&s,&t);tot=1;
    	for(int i=1;i<=m;i++){
    		int x,y,w;id[i]=tot+1;
    		scanf("%d%d%d",&x,&y,&w);
    		addl(x,y,w);
    	}
    	while(bfs())
    		dinic(s,inf);
    	for(int i=1;i<=n;i++)
    		if(!dfn[i])tarjan(i);
    	for(int i=1;i<=m;i++){
    		int x=a[id[i]^1].to,y=a[id[i]].to;
    		if(a[id[i]].w==0&&col[x]!=col[y])putchar('1');else putchar('0');putchar(' ');
    		if(a[id[i]].w==0&&col[x]==col[s]&&col[y]==col[t])putchar('1');else putchar('0');putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    计算任一输入的正整数的各位数字之和,并分析算法的时间复杂度
    10万数组去重,排序,找最多出现次数,(复杂度没有前一个博客好,随手写,有点烂)
    Maven环境搭建
    Tomcat内部结构及请求原理(转)
    Tomcat环境搭建
    斐讯面试记录—三线程交替打印ABC
    斐迅面试记录—SSL和TLS的区别
    斐迅面试记录—Http协议中的Header
    斐讯面试记录—强+软+弱+虚引用
    斐讯面试记录—TCP滑动窗口及拥塞控制
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14626495.html
Copyright © 2011-2022 走看看