zoukankan      html  css  js  c++  java
  • 【洛谷5934】[清华集训2012] 最小生成树(最小割)

    点此看题面

    • 给定一张(n)个点(m)条边的无向图,现在加入一条边((u,v,L)),问至少需要删去多少条边才能使得它既可能出现在最小生成树中,又可能出现在最大生成树中。
    • (nle2 imes10^4,mle2 imes10^5)

    最小割

    考虑(Kruskal)(MST)的思想,就是给边按权值排个序,然后贪心地能加就加。

    那么((u,v,L))能出现在最小生成树中,就说明所有边权小于(L)的边不能使得(u,v)连通,那么就直接把所有边权小于(L)的边连上求出最小割,即最大流。

    同理,能出现在最大生成树中,就说明所有边权大于(L)的边不能使得(u,v)连通,同样连边跑最大流即可。

    两个答案相加就是最终的答案。

    代码:(O(Dinic))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 20000
    #define M 200000
    using namespace std;
    int n,m,s,t,L;struct edge {int x,y,v;}e[M+5];
    namespace Dinic//网络流模板
    {
    	#define E(x) ((((x)-1)^1)+1)
    	#define add(x,y,f) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].F=f)
    	int ee,lnk[N+5],cur[N+5];struct edge {int to,nxt,F;}e[4*M+5];
    	I void Clear() {ee=0;for(RI i=1;i<=n;++i) lnk[i]=0;}//清空
    	I void Add(CI x,CI y,CI f) {add(x,y,f),add(y,x,0);}
    	int q[N+5],D[N+5];I bool BFS()
    	{
    		RI i,k,H=1,T=1;for(i=1;i<=n;++i) D[i]=0;D[q[1]=s]=1;W(H<=T&&!D[t])
    			for(i=lnk[k=q[H++]];i;i=e[i].nxt) e[i].F&&!D[e[i].to]&&(D[q[++T]=e[i].to]=D[k]+1);
    		return memcpy(cur,lnk,sizeof(cur)),D[t];
    	}
    	I int DFS(CI x=s,RI f=1e9)
    	{
    		if(x==t||!f) return f;RI i,g,res=0;for(i=cur[x];i;i=e[i].nxt)
    		{
    			if(!e[i].F||D[e[i].to]^(D[x]+1)||!(g=DFS(e[i].to,min(f,e[i].F)))) continue;
    			if(e[i].F-=g,e[E(i)].F+=g,res+=g,!(f-=g)) break;
    		}return cur[x]=i,res;
    	}
    	I int MaxFlow() {RI g=0;W(BFS()) g+=DFS();return g;}
    }
    int main()
    {
    	RI i;for(scanf("%d%d",&n,&m),i=1;i<=m;++i) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v);scanf("%d%d%d",&s,&t,&L);
    	for(i=1;i<=m;++i) e[i].v<L&&(Dinic::Add(e[i].x,e[i].y,1),Dinic::Add(e[i].y,e[i].x,1),0);//边权小于L的边
    	RI tot=Dinic::MaxFlow();Dinic::Clear();//两次网络流间要清空
    	for(i=1;i<=m;++i) e[i].v>L&&(Dinic::Add(e[i].x,e[i].y,1),Dinic::Add(e[i].y,e[i].x,1),0);//边权大于L的边
    	return printf("%d
    ",tot+=Dinic::MaxFlow()),0;//两次答案相加
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    if、else if 、else及switch...case使用小记(C#)
    c#基础知识
    流与文本文件操作(C#)
    .NET中的异常处理机制(一)
    .NET中的异常处理机制(二)
    在引用类型变量上调用虚方法和非虚方法的区别
    各位客官!鼠标点击一个Button之后究竟发生了什么?您知道么?(C#)
    接口和抽象类的使用场景以及多类继承存在的问题(c#)
    面向对象SOLID设计原则之Open-Closed原则
    stack和stack frame
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5934.html
Copyright © 2011-2022 走看看