P1195 口袋的天空

口袋的天空

题目背景

小杉坐在教室里,透过口袋一样的窗户看口袋一样的天空。

有很多云飘在那里,看起来很漂亮,小杉想摘下那样美的几朵云,做成棉花糖。

题目描述

给你云朵的个数 N N N,再给你 M M M 个关系,表示哪些云朵可以连在一起。

现在小杉要把所有云朵连成 K K K 个棉花糖,一个棉花糖最少要用掉一朵云,小杉想知道他怎么连,花费的代价最小。

输入格式

第一行有三个数 N , M , K N,M,K N,M,K

接下来 M M M 行每行三个数 X , Y , L X,Y,L X,Y,L,表示 X X X 云和 Y Y Y 云可以通过 L L L 的代价连在一起。

输出格式

对每组数据输出一行,仅有一个整数,表示最小的代价。

如果怎么连都连不出 K K K 个棉花糖,请输出 No Answer

样例 #1

样例输入 #1

3 1 2
1 2 1

样例输出 #1

1

提示

对于 30 % 30\% 30% 的数据, 1 ≤ N ≤ 100 1 \le N \le 100 1N100 1 ≤ M ≤ 1 0 3 1\le M \le 10^3 1M103

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 1 0 3 1 \le N \le 10^3 1N103 1 ≤ M ≤ 1 0 4 1 \le M \le 10^4 1M104 1 ≤ K ≤ 10 1 \le K \le 10 1K10 1 ≤ X , Y ≤ N 1 \le X,Y \le N 1X,YN 0 ≤ L < 1 0 4 0 \le L<10^4 0L<104

code

#include<bits/stdc++.h>
using namespace std;
#define FOR(i,n,s) for(int i=(s);i<=(n);i++)
const int MAX=1e4+5;
int n,m,k;
int cnt=0,sum=0;//sum记录边权和,cnt记录连了多少条边
struct node
{
	int u,v,w;
}edges[MAX];//存边的结构体

//
int f[MAX];//并查集的维护数组,表示根结点
int find(int x)
{
	if(x==f[x]) return x;
	else return f[x]=find(f[x]);
}//并查集查找函数:查找x的根节点
void init()
{
	FOR(i,n,1) f[i]=i;
}//并查集初始化函数:将每个结点的根结点先默认为它自己
int merge(int u,int v)
{
	return f[find(u)]=find(v);
}//并查集合并函数:将u和v的根结点合并
//
//并查集

//
bool cmp(node a,node b)
{
	return a.w<b.w;
}
bool kruskal()
{
	sort(edges+1,edges+1+m,cmp);//Kruskal最小生成树的思想,将边权按照从小到大排序
	FOR(i,m,1)
	{
		if(find(edges[i].u)!=find(edges[i].v))//如果个结点之间没有回路,则可以合并
		{
			merge(edges[i].u,edges[i].v);//合并
			cnt++;//计数器++
			sum+=edges[i].w;//更新最小边权和
		}
		if(cnt==n-k) return true;//多合并k个结点,则最多有n-k条边
	}
	return false;
}
//
//最小生成树
 
int main()
{
	cin>>n>>m>>k;
	init();
	FOR(i,m,1)
		cin>>edges[i].u>>edges[i].v>>edges[i].w;
	if(kruskal()) cout<<sum;
	else cout<<"No Answer";
	return 0;
}

ps:

单源最短路问题,所以考虑用Kruskal最小生成树解决,先按照边权从小到大的顺序排序,维护一个并查集数组f,然后通过判断两个结点之间有无回路,如果没有回路,则可以合并。合并后,用cnt记录添加的边数,最多合并k个结点,则最多有n-k条边,加个判断,直接输出答案然后return 0。最后如果跑完了循环还没有连完k个结点,输出No Answer

end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值