Joy OI【走廊泼水节】题解--最小生成树推论变式

  • 题目链接:

    http://joyoi.org/problem/tyvj-1391

  • 思路:

    首先这需要一个推论:

    “给定一张无向图,若用\(k(k条边构成一个生成森林(可以理解为多个互不相通的生成树),再从剩下的\(m-k\)条边中选出\(n-1-k\)条边构成改该图的最小生成树,则这\(m-k\)条边中一定包含连接两个不相连生成森林的最小边权的两点”

    这个推论是由这个定理得到:

    “一张无向图的最小生成树一定包含边权最小的那条边”,这个定理可以很容易地用反证法证得。

    那么我们就可以开始了,若连接两个不连通的生成森林最小边权为\(e\),根据推论,想要让它变成一张完全图而最小生成树保持不变,当然是让剩下的点相连边的权值为\(e+1\)

    那么让这两个生成森林变成完全图则需要\((e+1)*(size[A]*size[B]-1)\),\(size[K]\)为以K为父节点的生成森林所含的点数,减去1是因为两个之中已经有一条边权为\(e\)的边

    根据贪心的思想,我们显然所有边从小到大排序,如果两顶点不在一个森林里,那么合并,加入贡献。

  • 代码(话说并查集路径压缩一开始写错了,查了好久的错,真是太蒻了):

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long 
#define ri register int
using namespace std;
const int maxn=6005;
const int inf=0xfffffff;
struct Edge{
    int f,t,val;
    bool operator <(const Edge &b)const{
        return valinline void read(T &x){
    x=0;int ne=0;char c;
    while(!isdigit(c=getchar()))ne=c=='-';
    x=c-48;
    while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    x=ne?-x:x;
    return ;
}
int get(int x){
    if(fa[x]!=x)fa[x]=get(fa[x]); 
    return fa[x];//注意路径压缩写法 
}
int main(){
    int u,v,d;
    read(t);
    while(t--){
        int ans=0;
        memset(edge,0,sizeof(edge));
        read(n);
        for(ri i=1;i

转载于:https://www.cnblogs.com/Rye-Catcher/p/9152811.html

你可能感兴趣的:(Joy OI【走廊泼水节】题解--最小生成树推论变式)