[CCPC 2024 Shandong I] 多彩的生成树题解

题目描述

堡堡有很多彩色的节点。颜色的编号从 1 到 n(含两端),第 i 种颜色共有 ai​ 个节点。因为堡堡刚刚在算法课上学习了最小生成树问题,他打算利用这些节点做一些练习。

每一对节点都会被一条带有权值的边连接。每一条边的权值只和它两个端点的颜色有关。具体来说,令 cu​ 表示节点 u 的颜色,若一条边连接了节点 u 和 v,它的权值就是 bcu​,cv​​。

请帮助堡堡求出这张图的最小生成树的总权值。

请回忆:最小生成树是一张带权连通图的边的子集,这些边连通了所有节点,不会形成环,且总权值最小。

输入格式

有多组测试数据。第一行输入一个整数 T 表示测试数据组数。对于每组测试数据:

第一行输入一个整数 n(1≤n≤103)表示颜色的种数。

第二行输入 n 个整数 a1​,a2​,⋯,an​(1≤ai​≤106),其中 ai​ 表示颜色 i 有几个节点。

对于接下来的 n 行,第 i 行输入 n 个整数 bi,1​,bi,2​,⋯,bi,n​(1≤bi,j​≤106),其中 bi,j​ 表示两个端点的颜色分别为 i 和 j 的边的权值。保证对于所有 1≤i,j≤n 有 bi,j​=bj,i​。

保证所有数据 n 之和不超过 103。

输出格式

每组数据输出一行一个整数,表示最小生成树的总权值。

输入输出样例

输入 #1复制

3
3
100 1 1
1 100 2
100 100 1
2 1 100
2
3 3
100 1
1 100
1
1
5

输出 #1复制

102
5
0

思路

首先选出每一个中的一个节点,再直接连最优即可。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long t,n,a[1000006],b[1005][1005],f[1005],sd=0,lk=0,xx,yy,as=1e18+7;
struct one{
    long long x,y,w;
}aa[1000006];
bool cmp(one a1,one b1){
    return a1.w<b1.w;
}
long long find(long long a1){
    if(a1==f[a1]){
        return a1;
    }
    else{
        f[a1]=find(f[a1]);
        return f[a1];        
    }
}
int main(){
	cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            f[i]=i;
        }
        sd=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                cin>>b[i][j];
                if(i<=j){
                    aa[++sd]={i,j,b[i][j]};
                }
            }
        }
        sort(aa+1,aa+sd+1,cmp);
        lk=0;
        for(int i=1;i<=sd;i++){
            xx=find(aa[i].x);
            yy=find(aa[i].y);
            if(xx!=yy){
                f[yy]=xx;
                lk+=aa[i].w;
            }
        }
        for(int i=1;i<=n;i++){
            as=1e18+7;
            for(int j=1;j<=n;j++){
                as=min(as,b[i][j]);
            }
            lk+=(a[i]-1)*as;
        }
        cout<<lk<<endl;
    }
    return 0;
}

posted @ 2025-10-17 20:08  bz02_2023f2  阅读(2)  评论(0)    收藏  举报  来源