[BZOJ2561]最小生成树 最小割



给定一个无向加权图和一条边,问至少删掉几条边使得该边既可能出现在最小生成树上又可能出现在最大生成树上.
我们思考:一条边无论如何都不可能出现在最小生成树上,当且仅当只需要边权小于它的边就能使得它的两个端点联通.反之亦然,一条边可能出现在最小生成树上,当且仅当所有边权小于它的边都无法使得两端点联通.这就是一个最小割模型.

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 23333
#define M 233333
using namespace std;
struct Node
{
    int x,y,z;
}e[M];
inline bool cmp(Node a,Node b)
{
    return a.z<b.z;
}
int n,m,s,t,v;
int head[N],to[M<<2],next[M<<2],f[M<<2],tot=1;
inline void add(int x,int y)
{
    to[++tot]=y;f[tot]=1;next[tot]=head[x];head[x]=tot;
    to[++tot]=x;f[tot]=1;next[tot]=head[y];head[y]=tot;
}
inline void read(int &x)
{
    x=0;char c=getchar();
    while(c>'9'||c<'0')c=getchar();
    while(c<='9'&&c>='0')x=(x<<1)+(x<<3)+c-'0',c=getchar();
}
int ans;
queue<int>q;
int dis[N];
bool bfs()
{
    memset(dis,-1,sizeof dis);
    while(!q.empty())q.pop();
    q.push(s);dis[s]=0;
    int x;
    while(!q.empty())
    {
        x=q.front();q.pop();
        for(int i=head[x];i;i=next[i])if(dis[to[i]]==-1&&f[i])
        {
            dis[to[i]]=dis[x]+1;
            if(to[i]==t)return 1;
            q.push(to[i]);
        }
    }
    return 0;
}
int dinic(int x,int flow)
{
    if(x==t)return flow;
    int temp=flow,a;
    for(int i=head[x];i;i=next[i])if(dis[to[i]]==dis[x]+1&&f[i])
    {
        a=dinic(to[i],min(temp,f[i]));
        if(!a)dis[to[i]]=-1;
        temp-=a;
        f[i]-=a;f[i^1]+=a;
        if(!temp)break;
    }
    return flow-temp;
}
int maxflow()
{
    int re=0;
    while(bfs())re+=dinic(s,999999999);
    return re;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        read(e[i].x),read(e[i].y),read(e[i].z);
    }
    scanf("%d%d%d",&s,&t,&v);
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        if(e[i].z>=v)break;
        add(e[i].x,e[i].y);
    }
    ans+=maxflow();
    memset(head,0,sizeof head);
    memset(next,0,sizeof next);
    tot=1;
    for(int i=m;i>=1;i--)
    {
        if(e[i].z<=v)break;
        add(e[i].x,e[i].y);
    }
    ans+=maxflow();
    cout<<ans;
    return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注