zoukankan      html  css  js  c++  java
  • BZOJ_2561_最小生成树_最小割

    BZOJ_2561_最小生成树_最小割

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

    分析:

    如果所有边中有能使u,v连通且权值比L小的,那新加的这条边就不会出现在最小生成树上,最大生成树同理,那么问题就转化成求u,v之间的最小割,最小和最大分别做一次,相加即可。

    注意无向图连边时容量。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define N 20020
    #define M 400050
    #define inf 100000000
    struct A
    {
        int a,b,v;  
    }e[M];
    int S,T,ans;
    int head[N],to[M],nxt[M],cnt=1,flow[M],n,m;
    int dep[N];
    void add(int u,int v,int f)
    {
        to[++cnt]=v;
        nxt[cnt]=head[u];
        head[u]=cnt;
        flow[cnt]=f;    
    }
    bool bfs()
    {
        queue <int> q;
        memset(dep,0,sizeof(dep));
        dep[S]=1;q.push(S);
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=head[x];i;i=nxt[i])
            {
                if(!dep[to[i]]&&flow[i])
                {
                    dep[to[i]]=dep[x]+1;
                    if(to[i]==T)return 1;
                    q.push(to[i]);
                }
            }
        }
        return 0;
    }
    int dfs(int x,int mf)
    {
        if(x==T)return mf;
        int nf=0;
        for(int i=head[x];i;i=nxt[i])
        {
            if(dep[to[i]]==dep[x]+1&&flow[i])
            {
                int tmp=dfs(to[i],min(flow[i],mf-nf));
                nf+=tmp;
                flow[i]-=tmp;
                flow[i^1]+=tmp;
                if(nf==mf)break;
            }
        }
        dep[x]=0;
        return nf;
    }
    int dinic()
    {
        int f,sum=0;
        while(bfs())
        {
            while(f=dfs(S,inf))
            {
                sum+=f; 
            }
        }
        return sum;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int x,y,z;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].v);
        }
        scanf("%d%d%d",&S,&T,&z);
        for(int i=1;i<=m;i++)
        {
            if(e[i].v<z)
            {
                add(e[i].a,e[i].b,1);
                add(e[i].b,e[i].a,1);
            }
        }
        ans+=dinic();
        memset(head,0,sizeof(head));
        cnt=1;
        for(int i=1;i<=m;i++)
        {
            if(e[i].v>z)
            {
                add(e[i].a,e[i].b,1);
                add(e[i].b,e[i].a,1);
            }
        }
        printf("%d",ans+dinic());
    }
    
  • 相关阅读:
    C#无限分级实现,前端WEB页面接收,后台提供层级Json数据
    消息队列、OSS常用操作封装
    ABP增删改查代码片段
    WebApi实现验证授权Token,WebApi生成文档等
    项目收集-AutoMapper使用,事务,Json.Net序列化反序列化,代码生成调用等
    ssi服务器端指令详解(shtml)
    Linq常用List操作总结,ForEach、分页、交并集、去重、SelectMany等
    81.Search in Rotated Sorted Array II---二分变形
    48.Rotate Image
    89.Gray Code
  • 原文地址:https://www.cnblogs.com/suika/p/8434514.html
Copyright © 2011-2022 走看看