【洛谷】P1195 口袋的天空

文章讨论了如何使用并查集算法构建最小生成树,重点在于理解当边的数量等于n-k时,可以形成k个连通分量,即k个‘棉花糖’。通过排序边的权重并逐步连接,直到达到n-k条边,以达到最小总成本。如果边的数量不足n-k,则无法构建所需的连通结构。
摘要由CSDN通过智能技术生成

明显看出为最小生成树,

那么:难点在哪里呢?

   if(cnt==n-k)//******
        {
            flag=1;
            break;
        }

为什么是cnt==n-k呢而不是k呢?!!!

解释:(如果每个已经连在一起了就不能分开,不管多少个连在一起的算一个棉花糖***

上先在有两棵树,也就是有两个棉花糖,虽然1那边有三个点连接在一起,但是它们联通了就只算一个数不能分开。以此类推

!!!:

有一句话说的是 如果n个点被n-1条边连接的话,这一定是棵树。

那么:

连的边数 得到的树的个数

n-1 1(全部点都连接在一起了)

n-2 2(还剩一个点没有连接在一起,结果就是分成两部分(一个点的,和剩下所有点的))

n-3 3(以此类推)

... ...

n-k k

所以我们如果想要连出k棵树,就需要连n-k条边。

题目要求用n朵云连出k个棉花糖。

因为每个棉花糖都是连通的,

那么每个棉花糖就相当于是一棵树。

就是说要用n个节点连出k棵树。

也就是说要用n-k条边连出k棵树。

也就是说要花费连出n-k条边的代价。

既然一定要花费连出n-k条边的代价,

那么当然要选择代价最小的边连起来。

所以给每条可以连的边按代价从小到大排个序,

然后连n-k条边造k个最小生成树就可以了。

如果给的关系数m小于需要连的边数(n-k),是一定连不出k个树来的,因为m个关系只能连m条边。

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e3+10,M=1e4+10;
struct edge{
    int u,v,w;
}e[M];
int fa[N],n,m,k;
bool cmp(edge a,edge b)
{
    return a.w<b.w; 
}
int find(int x)
{
    if(fa[x]==x)return x;
    else
    {
        fa[x]=find(fa[x]);
        return fa[x];
    }
}
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++)
    {
        cin>>e[i].u>>e[i].v>>e[i].w;
    }
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
    }
    sort(e+1,e+1+m,cmp);
    int flag=0,cnt=0,sum=0;
    for(int i=1;i<=m;i++)
    {
        int f1=find(e[i].u);
        int f2=find(e[i].v);
        if(f1!=f2)
        {
            fa[f1]=f2;
            cnt++;
            sum+=e[i].w;
        }
        if(cnt==n-k)//******
        {
            flag=1;
            break;
        }
    }
    if(flag)
    cout<<sum;
    else
    cout<<"No Answer";
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值