连通森林(最小生成树)

题目描述

在有向图G中,如果两个顶点u,v间有一条从u到v的有向路径,同时还有一条从v到u的有向路径,则称两个顶点强连通。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向非强连通图的极大强连通子图,称为强连通分量。 不连通的单个的点也被称为一个强连通分量

现有一个n个点m条双向边的图,每条边有一个权值L,从m条边中选出若干条,形成一个含有k个强连通分量的图且选用的边的权值和最小

输入描述

第一行:输入三个数n、m、k,分别表示n个点,m条边,形成含有k个强连通分量的图

接下来m行:每行输入三个数,x、y、L,表示x和y之间有一条权值为L的双向边

对于 30% 的数据: n ≤ 100 m ≤ 1000 L ≤ 10000

对于100%的数据: n ≤ 1000 m ≤ 10000 L ≤ 10000

输出描述

如果可以形成含有k个强连通分量的图,输出选用边的权值和最小值

如果不能形成则输出“ No Answer”

样例

输入

3 1 2
1 2 1

输出

1

讲解

因为这道题是要求找到最小的权值和,所以这道题一定是某种求最小值的算法

且这个只要联通就行,无需成圈,所以是棵树

就是最小生成树

因为要分为K部分所以是K棵最小生成树

下面为代码

#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
	int x,y,l;
}a[10005];
//排序
bool cmp(const node a,const node b){
	return a.l<b.l;
}
int f[1005];
int n,m,k,cnt,sum;
//并查集的查找
int find(int x){
	if(x==f[x])
		return x;
	return f[x]=find(f[x]);
}
//并查集的初始化
void init(){
	for(int i=1;i<=1000;i++)
		f[i]=i;
}
//最小生成树
void kruskal(){
	sort(a+1,a+1+m,cmp);
	for(int i=1;i<=m;i++){
		int x=find(a[i].x),y=find(a[i].y);
		if(x==y)
			continue;
		sum+=a[i].l;
		cnt++;
		f[x]=y;
		if(cnt==n-k)
			break;
	}
	if(n-k==cnt)
		printf("%d",sum);
	else
		puts("No Answer");
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	init();
    //读入
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].l);
	kruskal();
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值