bzoj 2561 最小生成树 网络流

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=2561

做法

做这道题的时候,我想起了以前同学给我讲最小生成树的一个性质,基于kruskal的做法。
当你要加入一条边时,边权小于它的边一定都over了,而且哪些点构成一个联通块是确定了的,注意是小于,不是小于等于。
那么有了这个性质之后,这道题就非常easy了,考虑这条边能在最小生成树中,那么边权小于它的边连入之后这两个点一定还未联通,如果已经联通,就要删去最小数量的边使他联通,那么我们想就想到了最小割,所以图建出来跑一下最大流就行了,最大生成树的话同理,只要把大于它的边拿出来建图就行了。

代码

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#define LL long long
#define N (20005)
#define M (200005)
using namespace std;
int n,m,u,v,w,tot,S,T,ans;
int son[M<<1],nxt[M<<1],f[M<<1],head[N],cur[N],h[N],co[N];
struct node{
    int x,y,z;
}a[M];
template <typename T> void read(T&t) {
    t=0;
    bool fl=true;
    char p=getchar();
    while (!isdigit(p)) {
        if (p=='-') fl=false;
        p=getchar();
    }
    do {
        (t*=10)+=p-48;p=getchar();
    }while (isdigit(p));
    if (!fl) t=-t;
}
inline bool cmp(node a,node b){
    return a.z<b.z;
}
inline void add(int x,int y,int z){
    //printf("%d %d\n",x,y);
    son[++tot]=y,f[tot]=z,nxt[tot]=head[x],head[x]=tot;
}
int DFS(int u,int maxflow){
    if (u==T) return maxflow;
    int used=0;
    for (int p=cur[u];~p;p=nxt[p]){
        cur[u]=p;
        int v=son[p];
        if (f[p]>0&&h[v]+1==h[u]){
            int now=DFS(v,min(maxflow-used,f[p]));
            used+=now;
            f[p]-=now;
            f[p^1]+=now;
        }
        if (used==maxflow) return maxflow;
    }
    cur[u]=head[u];
    if (--co[h[u]]==0){
        h[S]=n;
    }
    h[u]++;
    co[h[u]]++;
    return used;
}
int main(){
    read(n),read(m);
    for (int i=1;i<=m;i++){
        read(a[i].x),read(a[i].y),read(a[i].z);
    }
    sort(a+1,a+m+1,cmp);
    read(u),read(v),read(w);
    tot=1;
    S=u,T=v;
    memset(head,-1,sizeof(head));
    memset(cur,-1,sizeof(cur));
    memset(h,0,sizeof(h));
    co[0]=n;
    for (int i=1;i<=m&&a[i].z<w;i++){
        add(a[i].x,a[i].y,1);
        add(a[i].y,a[i].x,1);
    }
    while (h[S]<n) ans+=DFS(S,10000007);
    //puts("stop");
    tot=1;
    memset(head,-1,sizeof(head));
    memset(cur,-1,sizeof(cur));
    memset(h,0,sizeof(h));
    memset(co,0,sizeof(co));
    co[0]=n;
    for (int i=m;i>=1&&a[i].z>w;i--){
        add(a[i].x,a[i].y,1);
        add(a[i].y,a[i].x,1);
    }
    while (h[S]<n) ans+=DFS(S,10000007);
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36056315/article/details/80560369