BZOJ 2561: 最小生成树(最小割)

原创 2015年11月17日 19:21:12

2561: 最小生成树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 957  Solved: 483
[Submit][Status][Discuss]

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。


考虑Kruskal算法de过程,若想让u,v出现在最小生成树中,则将边按权值排序后,比u-v的边权小的那些边不能使u和v联通,因此考虑最小割,求两遍最小割即可。


/**************************************************************
    Problem: 2561
    User: mogu
    Language: C++
    Result: Accepted
    Time:616 ms
    Memory:12992 kb
****************************************************************/
 
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#define ll long long 
using namespace std;
const int MAXN = 40000 + 10;
const int MAXM = 400000 + 10;
const int INF = 0x3f3f3f3f;
int read()
{
    int x = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f *= -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
struct Edge
{int to, next, cap, flow;}edge[MAXM];
int tot, head[MAXN];
int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
void init(){tot = 0; memset(head, -1, sizeof(head));}
void addedge(int u, int v, int w, int rw = 0)
{
    edge[tot].to = v; edge[tot].cap = w; edge[tot].next = head[u];
    edge[tot].flow = 0; head[u] = tot++;
    edge[tot].to = u; edge[tot].cap = rw; edge[tot].next = head[v];
    edge[tot].flow = 0; head[v] = tot++;
}
long long sap(int start, int end, int N)
{
    memset(gap, 0, sizeof(gap));
    memset(dep, 0, sizeof(dep));
    memcpy(cur, head, sizeof(head));
    int u = start; pre[u] = -1; gap[0] = N;
    long long ans = 0;
    while(dep[start] < N)
    {
        if(u == end)
        {
            long long Min = INF;
            for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
                if(Min > edge[i].cap - edge[i].flow)
                    Min = edge[i].cap - edge[i].flow;
            for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
            {
                edge[i].flow += Min;
                edge[i^1].flow -= Min;
            }
            u = start; ans += Min; continue;
        }
        bool flag = false;
        int v;
        for(int i=cur[u];i!=-1;i=edge[i].next)
        {
            v = edge[i].to;
            if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])
            {
                flag = true;
                cur[u] = pre[v] = i;
                break;
            }
        }
        if(flag)
        {u = v; continue;}
        int Min = N;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
            {
                Min = dep[edge[i].to];
                cur[u] = i;
            }
        }
        gap[dep[u]]--;
        if(!gap[dep[u]]) return ans;
        dep[u] = Min + 1;
        gap[dep[u]]++;
        if(u != start) u = edge[pre[u]^1].to;
    }
    return ans;
}
int n, m, U, V, L;
int u[MAXM], v[MAXM], w[MAXM];
int main()
{
    n = read(); m = read();
    for(int i=1;i<=m;i++)
    {
        u[i] = read(), v[i] = read(), w[i] = read();
    }
    long long ans = 0;
    U = read(), V = read(), L = read();
    init();
    for(int i=1;i<=m;i++)
    {
        if(w[i] < L) addedge(u[i], v[i], 1, 1);
    }
    ans += sap(U, V, n);
    init();
    for(int i=1;i<=m;i++)
    {
        if(w[i] > L) addedge(u[i], v[i], 1, 1);
    }
    ans += sap(U, V, n);
    printf("%lld\n", ans);
    return 0;
}


bzoj 2561: 最小生成树

Description  给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u...
  • lqybzx
  • lqybzx
  • 2014年10月16日 12:09
  • 491

【bzoj 2561】最小生成树(最小割)

传送门biu~ 根据Kruskal算法可知,比最小生成树上的边(u,v,w)权值小的所有边无法将u和v联通。那么在图中加入权值比L小的所有边,跑最小割就是这条边出现在最小生成树上时需要删掉最少的边数...
  • zP1nG
  • zP1nG
  • 2018年01月08日 20:55
  • 36

【BZOJ 2561】最小生成树 最小割

拿到题再一看数据范围怎么也是思考生成树把,居然是网络流qaq。。。 其实只要是换一个角度思考还是可以的,一棵树满足什么条件,至少就是任意两个节点之间有一条简单路径,而现在题目要求有不联通,那么再最优...
  • pbihao
  • pbihao
  • 2017年01月25日 15:26
  • 77

[BZOJ]2561 最小生成树 最小割

为什么删除最少的边判连通连最小割都没想到。。。估计是废了。。。 考虑Kruskal的过程(最小生成树)如果有一条边(u,v),若所有比他小的边能使u,v联通,这条边就不必加入生成树中,最大生成树也同...
  • DOFYPXY
  • DOFYPXY
  • 2017年04月25日 09:04
  • 164

BZOJ 2561 - 最小生成树 + 最小割

本题需要用一点M(in & ax)ST的性质。。 以MinestST(这英语也是十级水平。。)为例。。假设加入边(u, v),边权为L。然后我们把所有边权小于L的边都取出来单独看。这些边不能连通u, ...
  • yearwhk
  • yearwhk
  • 2015年12月16日 00:04
  • 165

BZOJ 2561 最小生成树 最小割

BZOJ 2561 最小生成树 最小割
  • wzq_QwQ
  • wzq_QwQ
  • 2015年07月24日 18:31
  • 1245

BZOJ 2561(最小生成树-最小割)

Description 给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),...
  • nike0good
  • nike0good
  • 2017年01月31日 11:48
  • 141

Bzoj2561:最小生成树:网络流,最小割

题目链接:最小生成树 发现如果这条边可能出现在最大生成树上的话,那么可以代替这条边的所有边都不连通,换句话说这条边是连接u,v必不可少的 于是我们把所有权值大于L的边建成一张边权去为1的图对U,V跑最...
  • qq_34025203
  • qq_34025203
  • 2016年05月03日 21:07
  • 248

[2561]:第二小整数

第二小整数Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Subm...
  • yang_chengfeng
  • yang_chengfeng
  • 2015年11月24日 20:45
  • 281

hdu 2561 第二小整数

第二小整数 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Su...
  • attack2001
  • attack2001
  • 2015年05月25日 23:23
  • 200
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:BZOJ 2561: 最小生成树(最小割)
举报原因:
原因补充:

(最多只允许输入30个字)