jzoj 2936_逐个击破_并查集

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jzoj 2936_逐个击破_并查集相关的知识,希望对你有一定的参考价值。

题目描述

三大战役的平津战场上,傅作义集团在以北平、天津为中心,东起唐山西至张家口的铁路线上摆起子一字长蛇阵,并企图在溃败时从海上南逃或向西逃窜。为了就地歼敌不让其逃走,maozedong制定了先切断敌人东洒两头退路然后再逐个歼灭敌人的战略方针。

秉承伟大军事家的战略思想,作为一个有智慧的军长你,遇到了一个类似的战场局面:

现在有N个城市,其中K个被敌方军团占领了,N个城市间有N-1条公路相连,破坏其中某条公路的代价是已知的,现在,告诉你K个敌方军团所在的城市,以及所有公路破坏的代价,请你算出花费最少的代价将这K个地方军团互相隔离开,以便第二步逐个击破敌人。


 

思路

最大生成树,可以用一个数组a来判断每一个并查集里面有几个是被占领的城市,在合并集合时转移即可


 

 

#include <stdio.h>
#include <algorithm>
using namespace std;
#define maxn 100005
struct edge
{
    int x, y, w;
}e[maxn];
int f[maxn], a[maxn];
int cmp(edge a, edge b)
{
    return a.w > b.w;
}
int find(int x)
{
    if (f[x] == x) return x;
    f[x] = find(f[x]);
    return f[x];
}
inline int read()
{
    int x=0,p=1;char ch=getchar();
    while (ch<0||ch>9){if (ch==-)p=-1;ch=getchar();}
    while (ch>=0&&ch<=9){x=(x<<1)+(x<<3)+ch-0;ch=getchar();}
    return x*p;
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++)
        f[i] = i;
    for (int i = 1; i <= m; i++)
    {
        int x = read();
        a[x] = 1;
    }
    double ans = 0;
    for (int i = 1; i < n; i++)
    {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        e[i] = (edge) {x, y, w};
        ans += w;
    }
    sort(e + 1, e + n, cmp);
    for (int i = 1; i < n; i++)
    {
        int xx = find(e[i].x), yy = find(e[i].y);
        if (a[xx] + a[yy] < 2)
        {
            f[xx] = yy;
            a[yy] += a[xx];
            a[xx] = 0;
            ans -= e[i].w;
        }
    }
    printf("%.lf\n", ans);
}

 

以上是关于jzoj 2936_逐个击破_并查集的主要内容,如果未能解决你的问题,请参考以下文章

LuoguP2700逐个击破并查集/生成树/正难则反By cellur925

p2700 逐个击破

P2700 逐个击破

bzoj 2936 [Poi 1999] 降水 - 并查集

[最小生成树][并查集]JZOJ 2940 生成输入数据

[并查集]JZOJ 5794 旅行