[BZOJ2561]最小生成树(最小割)

[BZOJ2561]最小生成树(最小割)

题面

给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?N ≤ 20000,M ≤ 200000,L ≤ 20000

分析

考虑Kruskal算法的过程,一条边\((u,v,w)\)能被加入最小生成树,当且仅当加入所有权值\(<w\)的边之后,\(u\)\(v\)不连通。

那么问题转化成删除最小的边,使得\(u,v\)不连通.直接建边权为1的边跑最小割即可,注意一条无向边要拆成两条。

最大生成树同理,对\(>w\)的边操作即可,最后把两个答案累加起来。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define INF 0x3f3f3f3f
#define maxn 20000
#define maxm 200000
using namespace std;
int n,m;
int U,V,W;
struct _edge{
    int from;
    int to;
    int len;
    friend bool operator < (_edge p,_edge q){
        return p.len<q.len;
    } 
}G[maxm+5];


namespace Dinic{
    struct edge{
        int from;
        int to;
        int next;
        int flow;
    }E[maxm*2+5];
    int head[maxn+5];
    int cur[maxn+5];
    int esz=1;
    void add_edge(int u,int v,int w){
    //	printf("%d->%d %d\n",u,v,w); 
        esz++;
        E[esz].from=u;
        E[esz].to=v;
        E[esz].flow=w;
        E[esz].next=head[u];
        head[u]=esz;
        esz++;
        E[esz].from=v;
        E[esz].to=u;
        E[esz].flow=0;
        E[esz].next=head[v];
        head[v]=esz;
    }
    int deep[maxn+5];
    bool bfs(int s,int t){
        memset(deep,0,sizeof(deep));
        queue<int>q;
        q.push(s);
        deep[s]=1;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=head[x];i;i=E[i].next){
                int y=E[i].to;
                if(!deep[y]&&E[i].flow){
                    deep[y]=deep[x]+1;
                    q.push(y);
                    if(y==t) return 1;
                }
            }
        }
        return 0;
    }
    int dfs(int x,int t,int minf){
        if(x==t) return minf;
        int rest=minf,k;
        for(int &i=cur[x];i;i=E[i].next){
            int y=E[i].to;
            if(E[i].flow&&deep[y]==deep[x]+1){
                k=dfs(y,t,min(rest,E[i].flow));
                E[i].flow-=k;
                E[i^1].flow+=k;
                rest-=k;
                if(k==0) deep[y]=0;
                if(rest==0) break; 
            }
        }
        return minf-rest;
    }
    int dinic(int s,int t){
        int ans=0;
        int now=0;
        while(bfs(s,t)){
            memcpy(cur,head,sizeof(head));
            while((now=dfs(s,t,INF))) ans+=now;
        } 
        return ans;
    }
    void clear(){
        esz=1;
        memset(head,0,sizeof(head));
    }
}


int main(){

    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d %d %d",&G[i].from,&G[i].to,&G[i].len);
    }	
    scanf("%d %d %d",&U,&V,&W);
    sort(G+1,G+1+m);
    int ans=0;
    for(int i=1;i<=m;i++){
        if(G[i].len<W){
            Dinic::add_edge(G[i].from,G[i].to,1);
            Dinic::add_edge(G[i].to,G[i].from,1);
        }
    }
    ans+=Dinic::dinic(U,V);
    Dinic::clear();
    for(int i=1;i<=m;i++){
        if(G[i].len>W){
            Dinic::add_edge(G[i].from,G[i].to,1);
            Dinic::add_edge(G[i].to,G[i].from,1);
        }
    }
    ans+=Dinic::dinic(U,V);
    printf("%d\n",ans);

} 

猜你喜欢

转载自www.cnblogs.com/birchtree/p/13403600.html