zoukankan      html  css  js  c++  java
  • 【bzoj2561】最小生成树 网络流最小割

    题目描述

    给定一个边带正权的连通无向图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;
    数据保证图中没有自环。

    输出

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

    样例输入

    3 2
    3 2 1
    1 2 3
    1 2 2

    样例输出

    1


    题解

    网络流最小割

    考虑Kruscal求最小生成树的过程:按照长度从小到大枚举每条边,如果某条边的两个点没有被连通,则加入这条边。

    所以某条边出现在最小生成树上的条件是:所有长度小于它的边不能使得这两点连通。

    于是可以把所有长度小于L的边加入到图中,然后要使得u和v不连通,就是求最小割。跑一遍即可。

    最大生成树同理。

    最后把两边的答案加起来即为最小删掉的边数。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define N 20010
    #define M 400010
    using namespace std;
    queue<int> q;
    int x[M] , y[M] , z[M] , head[N] , to[M] , val[M] , next[M] , cnt = 1 , s , t , dis[N];
    void add(int x , int y , int z)
    {
        to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
        to[++cnt] = x , val[cnt] = z , next[cnt] = head[y] , head[y] = cnt;
    }
    bool bfs()
    {
        int x , i;
        memset(dis , 0 , sizeof(dis));
        while(!q.empty()) q.pop();
        dis[s] = 1 , q.push(s);
        while(!q.empty())
        {
            x = q.front() , q.pop();
            for(i = head[x] ; i ; i = next[i])
            {
                if(val[i] && !dis[to[i]])
                {
                    dis[to[i]] = dis[x] + 1;
                    if(to[i] == t) return 1;
                    q.push(to[i]);
                }
            }
        }
        return 0;
    }
    int dinic(int x , int low)
    {
        if(x == t) return low;
        int temp = low , i , k;
        for(i = head[x] ; i ; i = next[i])
        {
            if(val[i] && dis[to[i]] == dis[x] + 1)
            {
                k = dinic(to[i] , min(temp , val[i]));
                if(!k) dis[to[i]] = 0;
                val[i] -= k , val[i ^ 1] += k;
                if(!(temp -= k)) break;
            }
        }
        return low - temp;
    }
    int main()
    {
        int n , m , i , w , ans = 0;
        scanf("%d%d" , &n , &m);
        for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &x[i] , &y[i] , &z[i]);
        scanf("%d%d%d" , &s , &t , &w);
        for(i = 1 ; i <= m ; i ++ )
            if(z[i] < w)
                add(x[i] , y[i] , 1);
        while(bfs()) ans += dinic(s , 1 << 30);
        memset(head , 0 , sizeof(head)) , cnt = 1;
        for(i = 1 ; i <= m ; i ++ )
            if(z[i] > w)
                add(x[i] , y[i] , 1);
        while(bfs()) ans += dinic(s , 1 << 30);
        printf("%d
    " , ans);
        return 0;
    }
    

     

  • 相关阅读:
    安装和配置nginx
    tomcat 生产发布脚本
    nginx 静态页面访问
    redis 搭建主从
    redis 安装
    perl 操作redis
    mysql 用户除了root一般不建议本地登录
    mysql创建用户
    mysql 查看排序集
    perl 安装Cpan
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7289412.html
Copyright © 2011-2022 走看看