【数据结构】新农村信息化/网络通信设计(最小生成树&并查集)

题面

【问题描述】
在智慧新农村建设中首先要有网络通信,假设通信公司要在n个村庄搭建通信网络,请求出最小的通信网络光缆总长度。

【输入形式】
第一行给出村庄个数n和可搭建的通信光纤通路m;
接下来的m行:每行给出一个三元组,数之间用空格隔开;前2列表示村庄可行的光纤连接,第3列表示需要的光缆长度。

【输出形式】
最小生成树的权值

【样例输入输出】

 

【样例说明】
权值是正整数,可能很大,但不需要考虑整型溢出问题


思路

这属于一道改编题,原题是“通信网络设计”,输出形式已经说的很明白了,要求最小生成树的权值。其实求最小花费,很明显是裸最小生成树。然后我们要求具体的联通块,从最小的点开始,路径上能够访问到的肯定是一个集合内的,最后排序一下。这里我们采用并查集算法来处理。为了防止输入输出数据过大,我们用快读读入。


AC_Code

#include <bits/stdc++.h>
#include <vector>
#include <stack>
#define ll long long 
#define db double 
using namespace std;

int n, m, f[119], vis[119], cnt[119]; 
vector<int> v[119], ansa[119];

inline int read() {
    int X=0, w=0;
	char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}

struct node{
    int u,v,w;
}a[110];


inline bool cmp(node x, node y){
    return x.w < y.w;
}

int find(int x) {
    if(f[x]==x)  return x;
    return find(f[x]);
}

void dfs(int x, int p) {
	for(int i=0; i<v[x].size(); i++) {
		if(!vis[v[x][i]]) {
			ansa[p].push_back(v[x][i]);
			vis[v[x][i]] = 1;
			dfs(v[x][i],p); 
		} 
	}
}

int main()
{
	n=read(),m=read();
    for(int i=0; i<m; i++){
        a[i].u=read(), a[i].v=read(), a[i].w=read();
        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;
		}
    }
    cout << sum << endl;
    return 0;
}

提高

假如题目变成需要为村庄间架设通信网络,使任何两个村庄间都可以实现通信连通(但不一定有直接的快速线路相连,只要互相间接有线路连通即可)。现有规划信息数据,列出了所有可能架设线路的两个村庄及其线路成本,请判断是否可以实现村村互联,如果可以,整个网络的最低成本是多少?如果不能实现村村互联,分成几个部分,各部分有哪些村庄?

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

我们就要分类讨论,根据不同情况判断输出了。

这样也就需要我们自己判断是否是用最小生成树结合其他的算法来解决问题。

于是我们需要判断是否能够联通,正确的代码就要进行补充更改(放在下面):

#include <bits/stdc++.h>
#include <vector>
#include <stack>
#define ll long long 
#define db double 
using namespace std;
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;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

米莱虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值