tsinsen1277 最小生成树

来源:互联网 发布:凌志软件 编辑:程序博客网 时间:2024/05/22 10:23

试题来源   中国国家队清华集训 2011-2012 第一天 问题描述
  给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L
(u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?
输入格式   第一行包含用空格隔开的两个整数,分别为N和M;
  接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。   最后一行包含用空格隔开的三个整数,分别为u,v,和
L;   数据保证图中没有自环。 输出格式   输出一行一个整数表示最少需要删掉的边的数量。

一条边uv可能在最小生成树中,当且仅当权值小于它的边不能起到它的效果,也就是不能使uv联通。把所有权值小于它的边找出来,要把uv分开,只需要求最小割。
最大生成树同理。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int oo=0x3f3f3f3f;int fir[20010],ne[400010],to[400010],l[400010],w[400010],f[20010],que[20010],n,m,s,t;void add(int num,int u,int v,int x){    ne[num]=fir[u];    fir[u]=num;    to[num]=v;    l[num]=x;}bool bfs(){    int u,v,hd=1,tl=1;    for (int i=1;i<=n;i++) f[i]=0;    f[s]=1;    que[1]=s;    while (hd<=tl)    {        u=que[hd++];        for (int i=fir[u];i;i=ne[i])            if (!f[v=to[i]]&&w[i])            {                f[v]=f[u]+1;                que[++tl]=v;            }    }    return f[t];}int dfs(int u,int lim){    if (u==t) return lim;    int x,ret=0,v;    for (int i=fir[u];i&&ret<lim;i=ne[i])        if (w[i]&&f[v=to[i]]==f[u]+1)        {            x=dfs(v,min(lim-ret,w[i]));            ret+=x;            w[i]-=x;            w[i^1]+=x;        }    if (!ret) f[u]=0;    return ret;}int main(){    int u,v,ww,x,ans=0;    scanf("%d%d",&n,&m);    for (int i=1;i<=m;i++)    {        scanf("%d%d%d",&u,&v,&x);        add(i*2,u,v,x);        add(i*2+1,v,u,x);    }    scanf("%d%d%d",&s,&t,&ww);    for (int i=1;i<=n;i++)        for (int j=fir[i];j;j=ne[j])            w[j]=(l[j]<ww);    while (bfs()) while (x=dfs(s,oo)) ans+=x;    for (int i=1;i<=n;i++)        for (int j=fir[i];j;j=ne[j])            w[j]=(l[j]>ww);    while (bfs()) while (x=dfs(s,oo)) ans+=x;    printf("%d\n",ans);}
0 0
原创粉丝点击