关闭

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

176人阅读 评论(0) 收藏 举报
分类:

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;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:104846次
    • 积分:3707
    • 等级:
    • 排名:第9005名
    • 原创:275篇
    • 转载:8篇
    • 译文:0篇
    • 评论:8条
    最新评论