题目
某个局域网内有 n(n≤100) 台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成网络卡的现象。因为连接计算机的网线本身不同,所以有一些连线不是很畅通,我们用 f(i,j) 表示 i,j 之间连接的畅通程度,f(i,j) 值越小表示 i,j 之间连接越通畅,f(i,j) 为 0 表示 i,j 之间无网线连接。
题目描述
需要解决回路问题,我们将除去一些连线,使得网络中没有回路,并且被除去网线的 ∑f(i,j) 最大,请求出这个最大值。
输入格式
第一行两个正整数 n,k。
接下来的 k 行每行三个正整数 i,j,m 表示 i,j 两台计算机之间有网线联通,通畅程度为 m。
输出格式
一个正整数,∑f(i,j) 的最大值。
解析
根据题目可知,局域网是全部联通的,只是有多余线路导致整个网络形成了回路,要求出被除去网线的 ∑f(i,j),也就是要使用最少的 ∑f(i,j) ,将网络连接起来(把 ∑f(i,j) 看作俩台电脑之间所连网线的长度会好理解一些),所以我可以先把所有电脑网线都拔开,然后使用最短的网线将这些电脑连接起来,剩余的网线长度就是被除去网线长度的最大值。
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
int N,K;
// 用来记录输入的结构体
struct cpt{
int x,y,l;
};
// 100台电脑最大连接数量也就是4950,下标从1开始,所以4951刚刚好
struct cpt c[4951];
// 使用并查集,用来记录每台电脑的上级,下标从1开始
int par[101];
// 并查集find函数,用来寻找某节点的上级
int find1(int x) {
int r=x;
// 寻找该节点的上级,直到找到一个节点的上级就是自己退出循环
while(par[r]!=r){
r=par[r];
}
// 此处 r 表示传入 x 的最上级
int i=x,j;
// 压缩路径,将传入 x 的上级设为 r
while(i!=j){
j=par[r];
par[i]=j;
i=j;
}
return r;
}
// 并查集join函数,用来将新的节点加入网络
void join(int x, int y) {
// 如果上级不一样,修改设置为相同
int fx=find1(x), fy=find1(y);
if(fx!=fy){
par[fx]=fy;
}
}
// 检查par数组中有几个区块(有几个上级为自己的节点)
int check(){
int sum = 0;
for(int i=1; i<=N; i++)
if(par[i]==i)
sum ++;
return sum;
}
// 使用快排的cmp,从小到大
bool cmp(cpt a, cpt b){
return a.l<b.l;
}
int main(){
// 用来记录网络中网线的最大长度
int length=0;
scanf("%d%d",&N,&K);
for(int i=1; i<=N; i++)
par[i]=i; // 设置每台电脑的上级都为自己
for(int i=1; i<=K; i++){
scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].l);
// 记录网线长度
length+=c[i].l;
}
// 将所有节点之间的连接按照网线长度进行排序
sort(c+1, c+1+K, cmp);
// 对所有网线进行循环
for(int i=1; i<=K; i++){
int r1 = find1(c[i].x);
int r2 = find1(c[i].y);
// 如果这两台电脑的上级不同,则使用网线将这俩个区块连接起来
// 上级不同说明这两台电脑之间没有连接,此时取出的网线长度还是从小到大排列的
// 所以使用这个网线连接可以确保使用的是最短的网线
if(r1 != r2){
join(c[i].x,c[i].y);
// 从总长度中减去使用的网线长度
length-=c[i].l;
}
}
// 剩余的长度即为最大长度
printf("%d",length);
}