题面
【问题描述】
在智慧新农村建设中首先要有网络通信,假设通信公司要在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;
}