• BZOJ 2561: 最小生成树【最小割/最大流】


    Description

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

    Input

      第一行包含用空格隔开的两个整数,分别为N和M;
      接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。
      最后一行包含用空格隔开的三个整数,分别为u,v,和 L;
      数据保证图中没有自环。

    Output

     输出一行一个整数表示最少需要删掉的边的数量。

    Sample Input

    3 2
    3 2 1
    1 2 3
    1 2 2

    Sample Output

    1

    HINT

    对于20%的数据满足N ≤ 10,M ≤ 20,L ≤ 20;
      对于50%的数据满足N ≤ 300,M ≤ 3000,L ≤ 200;
      对于100%的数据满足N ≤ 20000,M ≤ 200000,L ≤ 20000。

    Source

    2012国家集训队Round 1 day1

    思路:首先白书中有这么一个命题:如果在图中存在一个环,使得一条边为环中的最大值,那么这条最大值的边显然不可能是MST中的边,于是猜测了一个相似的命题:如果不存在一个环使得这个边为最大值,那么一定存在一个MST使得这条边为MST中的边

    然后仔细想想这个命题好像是有问题的,于是往kruscal方面考虑,如果将边排序了以后从小到大加,则加边过程中u到v显然不能联通,不然就得删边,在看了解题报告后证实了这个想法,于是对于一条边一定存在一个MST使得这条边为MST中的边的充要条件为比这条边小的边一定不能和这条边成环,于是结果就很显然了

    #include <stdio.h>

    #include <iostream>

    #include<queue>

    #include <string.h>

    #include <algorithm>

    #define maxn 1000005

    #define maxm 1000005

    #define inf 0x3f3f3f3f

    int head[maxn],next[maxn],point[maxn],flow[maxn];

    int ans=0,now=0,dist[maxn],que[maxn];

    using namespace std;

    struct T

    {

        int x;int y;int v;

    }a[maxn];

    inline bool operator <(T a,T b){return a.v<b.v;}

    void add(int x,int y,int v)

    {

        next[++now]=head[x];

        head[x]=now;

        point[now]=y;

        flow[now]=v;

        next[++now]=head[y];

        head[y]=now;

        point[now]=x;

        flow[now]=0;

    }

    int bfs(int s,int t)

    {

        memset(dist,-1,sizeof(dist));

        dist[s]=0;

        int l=0,r=0;

        que[++r]=s;

        while(l<r)

        {

            int u=que[++l];

            for(int i=head[u];i;i=next[i])

            {

                if(dist[point[i]]==-1&&flow[i])

                {

                    int k=point[i];

                    dist[k]=dist[u]+1;

                    que[++r]=k;

                }

            }

        }

        return dist[t]!=-1;

    }

    int dfs(int s,int d,int t)

    {

        if(s==t)return d;

        int res=0;

        for(int i=head[s];i&&res<d;i=next[i])

        {

            int u=point[i];

            if(flow[i]>0 &&dist[u]==dist[s]+1)

            {

                int dd=dfs(u,min(d-res,flow[i]),t);

                if(dd>0)

                {

                    flow[i]-=dd;

                    flow[((i-1)^1)+1]+=dd;

                    res+=dd;

                }

            }

        }

        if(res==0)dist[s]=-1;

        return res;

    }

    int main()

    {

        int n,m,s,t,l;

        scanf("%d%d",&n,&m);

        for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);

        scanf("%d%d%d",&s,&t,&l);

        sort(a+1,a+1+m);

        for(int i=1;i<=m;i++)

        {

            if(a[i].v>l)

            {

                add(a[i].x,a[i].y,1);

                add(a[i].y,a[i].x,1);

            }

        }

        while(bfs(s,t))

        {

            ans+=dfs(s,inf,t);

        }

        now=0;

        memset(head,0,sizeof(head));

        for(int i=1;i<=m;i++)

        {

            if(a[i].v<l)

            {

                add(a[i].x,a[i].y,1);

                add(a[i].y,a[i].x,1);

            }

        }

        while(bfs(s,t))

        {

            ans+=dfs(s,inf,t);

        }

        printf("%d ",ans);

        return 0;

    }

  • 相关阅读:
    想更改Github仓库中的某个文件结构
    记git一些基本用法
    剑指Offer-Python(16-20)
    剑指Offer-Python(11-15)
    初次使用flask
    Python的Cmd模块的简易运用学习
    SQL-全称量词查询
    线段树模板1
    OJ输入输出超时(C++)
    二叉查找树(BST)定义
  • 原文地址:https://www.cnblogs.com/philippica/p/4083710.html
Copyright © 2020-2023  润新知