题解:洛谷 P1195 口袋的天空

【题目来源】

洛谷: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
posted @ 2026-03-19 17:34  团爸讲算法  阅读(1)  评论(0)    收藏  举报