题目
某个局域网内有 n 台计算机和 k 条 双向 网线,计算机的编号是 1∼n。由于搭建局域网时工作人员的疏忽,现在局域网内的连接形成了回路,我们知道如果局域网形成回路那么数据将不停的在回路内传输,造成网络卡的现象。
注意:
- 对于某一个连接,虽然它是双向的,但我们不将其当做回路。本题中所描述的回路至少要包含两条不同的连接。
- 两台计算机之间最多只会存在一条连接。
- 不存在一条连接,它所连接的两端是同一台计算机。
因为连接计算机的网线本身不同,所以有一些连线不是很畅通,我们用 f(i,j) 表示 i,j 之间连接的畅通程度,f(i,j) 值越小表示 i,j 之间连接越通畅。
现在我们需要解决回路问题,我们将除去一些连线,使得网络中没有回路且不影响连通性(即如果之前某两个点是连通的,去完之后也必须是连通的),并且被除去网线的 Σf(i,j) 最大,请求出这个最大值。
输入格式
第一行两个正整数 n,k。
接下来的 k 行每行三个正整数 i,j,m 表示 i,j 两台计算机之间有网线联通,通畅程度为 m。
输出格式
一个正整数,表示被除去网线的 Σf(i,j) 的最大值。
数据范围
1≤n≤100
0≤k≤200
1≤f(i,j)≤1000
输入样例:
5 5
1 2 8
1 3 1
1 5 3
2 4 5
3 4 2
输出样例:
8
思路
Kruskal算法:俗称加边法
使用小根堆储存所有的边(L 边长,x 端点1,y 端点2),初始状态所有点的祖先都为其本身。
依次拿出小根堆中边长最小的边,如果两个端点x,y的祖先find(x) == find(y)【祖先相同】,则不做任何操作,如果find(x) != find(y) 【祖先不同】则将x的祖先节点的祖先节点变为y的祖先节点,最小生成树大小加上 L 。
循环上述操作,直到小根堆中没有任何边,输出答案。
=========================================================================
Prim算法:俗称加点法
建立一个已经确定最小距离的集合,每次找出不在这个集合内且距离这个集合最小的点加入集合中,最小生成树大小加上该点到集合的距离,每次循环加入一个点,循环n次加入n个点。
当所有点都被加入集合中就确定了最小生成树的大小。
代码
Kruskal版:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,pair<int,int>> PII;
const int N = 1e3 + 10;
int n,m;
priority_queue<PII,vector<PII>,greater<>> heap;
int p[N];
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++) p[i] = i;
int sum = 0;
while(m --)
{
int a,b,c;
cin >> a >> b >> c;
sum += c;
heap.push({c,{a,b}});
}
int cnt = 0;
while(!heap.empty())
{
auto t = heap.top();
heap.pop();
int x = find(t.second.first);
int y = find(t.second.second);
int dist = t.first;
if(x == y) continue;
p[x] = y;
cnt += dist;
}
cout << sum - cnt << endl;
return 0;
}
Prim版 :
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n,k;
int h[N],e[N],ne[N],w[N],idx;
int dist[N];
int ans,flag;
bool st[N];
void add(int a,int b,int c)
{
w[idx] = c,e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}
void prim()
{
memset(dist,0x3f,sizeof(dist));
dist[1] = 0;
int _ = n;
while(_ --)
{
int t = -1;
for(int i = 1; i <= n; i ++)
{
if(!st[i] && (t == -1 || dist[t] > dist[i]))
t = i;
}
if(dist[t] == 0x3f3f3f3f) dist[t] = 0;
st[t] = true;
ans += dist[t];
for(int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
dist[j] = min(dist[j],w[i]);
}
}
}
int main()
{
memset(h,-1,sizeof(h));
cin >> n >> k;
for(int i = 1; i <= k; i ++)
{
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);
add(b,a,c);
flag += c;
}
prim();
cout << flag - ans << endl;
return 0;
}
难度:简单 |
时/空限制:1s / 64MB |
总通过数:6881 |
总尝试数:10454 |
来源:《信息学奥赛一本通》 |
算法标签 |
题目来自: 1141. 局域网 - AcWing题库