题解:洛谷 P1195 口袋的天空
【题目来源】
【题目描述】
给你云朵的个数 \(N\),再给你 \(M\) 个关系,表示哪些云朵可以连在一起。
现在小杉要把所有云朵连成 \(K\) 个棉花糖,一个棉花糖最少要用掉一朵云,小杉想知道他怎么连,花费的代价最小。
【输入】
第一行有三个数 \(N,M,K\)。
接下来 \(M\) 行每行三个数 \(X,Y,L\),表示 \(X\) 云和 \(Y\) 云可以通过 \(L\) 的代价连在一起。
【输出】
对每组数据输出一行,仅有一个整数,表示最小的代价。
如果怎么连都连不出 \(K\) 个棉花糖,请输出 No Answer。
【输入样例】
3 1 2
1 2 1
【输出样例】
1
【算法标签】
《洛谷 P1195 口袋的天空》 #图论# #并查集# #生成树#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 10005, INF = 1e9;
int n, m, k, ans; // n是点数,m是边数
int p[N]; // 并查集的父节点数组
struct Edge // 存储边
{
int a, b, w;
bool operator < (const Edge &E)const
{
return w < E.w; // 按边权从小到大排序
}
} edges[M];
int find(int x) // 并查集核心操作
{
if (p[x] != x)
{
p[x] = find(p[x]);
}
return p[x];
}
int kruskal()
{
sort(edges + 1, edges + m + 1); // 从1开始读入数据
for (int i = 1; i <= n; i++)
{
p[i] = i; // 初始化并查集
}
int res = 0, cnt = 0; // res记录总边权,cnt记录已选择的边数
for (int i = 1; i <= m; i++)
{
// 当已选择的边数达到k时停止
if (cnt == k)
{
break;
}
int a = edges[i].a, b = edges[i].b, w = edges[i].w;
a = find(a), b = find(b);
if (a != b) // 如果两个连通块不连通,则将这两个连通块合并
{
p[a] = b;
res += w;
cnt++;
}
}
// 检查是否成功选择了k条边
if (cnt == k)
{
return res;
}
else
{
return INF; // 无法选择k条边
}
}
int main()
{
cin >> n >> m >> k;
k = n - k; // 将连通块数量k转换为需要选择的边数
for (int i = 1; i <= m; i++)
{
cin >> edges[i].a >> edges[i].b >> edges[i].w;
}
ans = kruskal();
if (ans == INF)
{
cout << "No Answer" << endl;
}
else
{
cout << ans << endl;
}
return 0;
}
【运行结果】
3 1 2
1 2 1
1
浙公网安备 33010602011771号