局域网

//最小生成树入门题目,用克鲁斯卡尔算法,
//要用并查集 + 路径压缩基本操作
/*

问题 B: 局域网
时间限制: 1 Sec 内存限制: 128 MB
提交: 43 解决: 8
[提交] [状态] [讨论版] [命题人:admin]
题目描述
某个局域网内有n(n<=100)台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成网络卡的现象。因为连接计算机的网线本身不同,所以有一些连线不是很畅通,我们用f(i,j)表示i,j之间连接的畅通程度,f(i,j)值越小表示i,j之间连接越通畅,f(i,j)为0表示i,j之间无网线连接。( f(i,j) <= 1000 )
现在需要解决回路问题,我们将除去一些连线,使得网络中没有回路,并且被除去网线的Σf(i,j)最大,请求出这个最大值。
输入
第一行两个正整数n k
接下来的k行每行三个正整数i j m表示i,j两台计算机之间有网线联通,通畅程度为m。
输出
输出一个正整数,Σf(i,j)的最大值
样例输入 Copy
5 5
1 2 8
1 3 1
1 5 3
2 4 5
3 4 2
样例输出 Copy
8
提示
最小生成树

*/

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
using namespace std;
struct node{
int f, t;//f为第一台电脑,t为第二台电脑
int v;//边
};
node edge[10005];//最多100台电脑,最多有10000条边
int ans;
int pre[105];//并查集容器
int s1, s2;
bool cmp(node x, node y){//比较,得到最小边
return x.v < y.v;
}
int find(int x){
//并查集+路径压缩
if(x != pre[x]){//如果x不是自身的根的话就递归找到根,把沿途的根(伪根)都换成实根
//降低树的高度,虽然第一次查找时复杂度没变,但以后查找要快很多
pre[x] = find(pre[x]);
}
return pre[x];//返回实根
}
int main(){
int k, n, d1, d2;
while(cin >> n >> k){//输入电脑数,边数
s1 = 0;//s1用来统计初始总边长
s2 = 0;
for(int i = 0; i <= n; i++){//各自为政
//初始化并查集数组
pre[i] = i;//自身是自身的根
}
for(int i = 0; i < k; i++){
cin >> edge[i].f >> edge[i].t >> edge[i].v;
s1 += edge[i].v;
}
sort(edge, edge + k, cmp);//从小到大排序
ans = 0;
/*算法核心:并查集保证生成的树,而边数 == 顶点数 - 1保证不会有圈*/
for(int i = 0; i < k; i++){
//进行克鲁斯卡尔 + 并查集操作
d1 = find(edge[i].f);
d2 = find(edge[i].t);
if(d1 != d2){//两个节点不在同一个集合
pre[d2] = d1;//将集合2并入集合1
ans++;//边树
s2 += edge[i].v;
if(ans >= n - 1)//生成最小生成树的条件 (简单讲就是:边数 == 顶点数 - 1)
break;
}
}
cout << s1 - s2;//答案为边的和减去最小生成树的树值
}
return 0;
}

posted @ 2019-03-05 09:54  kakaluotedj  阅读(131)  评论(0)    收藏  举报