通信网络设计(最小生成树+图的联通)

12 篇文章 0 订阅
3 篇文章 0 订阅

题目详情:

假设你是电信工程师,需要为村庄间架设通信网络,使任何两个村庄间都可以实现通信连通(但不一定有直接的快速线路相连,只要互相间接有线路连通即可)。现有规划信息数据,列出了所有可能架设线路的两个村庄及其线路成本,请判断是否可以实现村村互联,如果可以,整个网络的最低成本是多少?如果不能实现村村互联,分成几个部分,各部分有哪些村庄?
输入格式:
第一行给出村庄数目n (1≤n≤50)和候选线路条数m≥0;随后的m行,每行给出3个正整数,分别是该条线路直接连通的两个村庄的编号(编号从1开始起编)以及该线路的建设成本。

输出格式: 输出是否实现村村互联的判断结果。 如果是,再输出整个网络的最低成本。
如果不能实现互联,输出分成几部分,每部分有哪些村庄。每个不连通部分的中的顶点是从小到大 。各部分的前后顺序也是按第一个顶点从小到大列出。

输入样例: 在这里给出一组输入。例如:
6 10
1 2 6
1 5 10
1 6 12
2 4 5
2 6 8
2 3 3
3 4 7
4 5 9
4 6 11
5 6 16
输出样例:
在这里给出相应的输出。例如:
YES!
Total cost:31

分析:求最小花费,很明显是裸的最小生成树。然后是求具体的联通块,我的想法是 从最小点开始dfs,路径上能够访问到的肯定是一个集合内的,最后排一下序即可。(突然发现既然已经用了并查集,那么可以不用再dfs了。。。)

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int N=1e2+5;

int n,m,f[N],vis[N],cnt;
vector<int>v[N],ans[N];
struct node{
	int u,v,w;
}a[N];
//按照边权升序排序
bool cmp(node x,node y){
	return x.w<y.w;
}
//路径压缩的并查集
int find(int x){
	return x==f[x]?x:f[x]=find(f[x]);
}
void dfs(int x,int no){
	for(int i=0;i<v[x].size();i++){
		if(!vis[v[x][i]]){
			ans[no].push_back(v[x][i]);
			vis[v[x][i]]=1;
			dfs(v[x][i],no);
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=0;i<m;i++){
		cin>>a[i].u>>a[i].v>>a[i].w;
		v[a[i].u].push_back(a[i].v);
		v[a[i].v].push_back(a[i].u);
	}
	int num=0,sum=0;
	for(int i=0;i<=n;i++)
		f[i]=i;
    sort(a,a+m,cmp);
	for(int i=0;i<m;i++){
		int x=a[i].u,y=a[i].v;
		x=find(x),y=find(y);
		if(x!=y){//合并不在一个集合内的,更新总代价
			f[x]=y;
			num++;
			sum+=a[i].w;
			//已经联通了
			if(num>=n-1)	break;
		}
	}
	if(num<n-1){
		cout<<"NO!"<<endl;
		for(int i=1;i<=n;i++){
			if(!vis[i]){
				vis[i]=1;
				ans[cnt].push_back(i);
				dfs(i,cnt++);
			}
		}
		for(int i=0;i<cnt;i++){
			sort(ans[i].begin(),ans[i].end());
			cout<<i+1<<" part:";
			for(int j=0;j<ans[i].size();j++){
				if(j)	cout<<" ";
				cout<<ans[i][j];
			}
			cout<<endl;
		}
	}else{
		cout<<"YES!"<<endl;
		cout<<"Total cost:"<<sum<<endl;
	}
	return 0;
}
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值