bzoj2561-最小生成树

题目

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

分析

一开始是从最小生成树的Kruskal想,想到了先求两次最小生成树再用优先级求两次最大生成树,后来发现是错的。正解网络流。 若一条边可以出现在最小生成树上,那么就说明比它小的边不能把这两个点联通,最大生成树同理。问题转化成了求比这条边小的边中去掉多少个不联通,于是可以想到用每条边流量为1的最小割。对比\(w\)小和大分别求两次,加起来就是答案。

代码

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<queue>
#define F(x) for (int i=h[x],v=e[i].v,w=e[i].w;~i;i=e[i].nxt,v=e[i].v,w=e[i].w)
using namespace std;
int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=2e4+10;
const int maxm=2e5+10;
const int inf=1e9+10;
struct gp {
    int u,v,w;
} a[maxm];
struct edge {
    int v,w,nxt;
} e[maxm<<2];
int h[maxn],tot=0,nowinf;
void add(int u,int v,int w) {
    e[tot]=(edge){v,w,h[u]};
    h[u]=tot++;
}
void adde(int u,int v,int w) {
    add(u,v,w),add(v,u,0);
}
int dis[maxn];
queue<int> q;
bool bfs(int s,int t) {
    q.push(s);
    memset(dis,0x3f,sizeof dis);
    nowinf=dis[0];
    dis[s]=0;
    while (!q.empty()) {
        int u=q.front();
        q.pop();
        F(u) if (w>0 && dis[v]==nowinf) {
            dis[v]=dis[u]+1;
            q.push(v);
        }
    }
    return dis[t]!=nowinf;
}
int Flow(int x,int t,int mi) {
    if (x==t) return mi;
    int tmp=0;
    F(x) if (w>0 && dis[v]==dis[x]+1) {
        int now=Flow(v,t,min(mi,w));
        mi-=now;
        e[i].w-=now;
        e[i^1].w+=now;
        tmp+=now;
        if (mi==0) break;
    }
    if (!tmp) dis[x]=-1;
    return tmp;
}
int maxflow(int s,int t) {
    int ret=0;
    while (bfs(s,t)) {
        ret+=Flow(s,t,inf);
    }
    return ret;
}
int main() {
    #ifndef ONLINE_JUDGE
        freopen("test.in","r",stdin);
    #endif
    int n=read(),m=read();
    for (int i=1;i<=m;++i) a[i].u=read(),a[i].v=read(),a[i].w=read();
    int s=read(),t=read(),w=read();
    memset(h,0xff,sizeof h),tot=0;
    for (int i=1;i<=m;++i) if (a[i].w<w) adde(a[i].u,a[i].v,1),adde(a[i].v,a[i].u,1); 
    int fa=maxflow(s,t);
    memset(h,0xff,sizeof h),tot=0;
    for (int i=1;i<=m;++i) if (a[i].w>w) adde(a[i].u,a[i].v,1),adde(a[i].v,a[i].u,1);
    int fb=maxflow(s,t);
    int ans=fa+fb;
    printf("%d\n",ans);
}
posted @ 2017-04-17 20:13  permui  阅读(371)  评论(0编辑  收藏  举报