给定一个带权无向图,如果是连通图,则至少存在一棵最小生成树,有时最小生成树并不唯一。本题就要求你计算最小生成树的总权重,并且判断其是否唯一。 输入格式:首先第一行给出两个整数:无向图中顶点数 N(≤500)和边数 M。随后 M 行,每行给出一条边的两个端点和权重,格式为“顶点1 顶点2 权重”,其中顶点从 1 到N 编号,权重为正整数。题目保证最小生成树的总权重不会超过 230。 输出格式:如果存在最小生成树,首先在第一行输出其总权重,第二行输出“Yes”,如果此树唯一,否则输出“No”。如果树不存在,则首先在第一行输出“No MST”,第二行输出图的连通集个数。 |
输入样例 1:
5 7 1 2 6 5 1 1 2 3 4 3 4 3 4 1 7 2 4 2 4 5 5
输出样例 1:
11 Yes
输入样例 2:
4 5 1 2 1 2 3 1 3 4 2 4 1 2 3 1 3
输出样例 2:
4 No
输入样例 3:
5 5 1 2 1 2 3 1 3 4 2 4 1 2 3 1 3
输出样例 3:
No MST 2
考察 : 最小生成树的深度理解 |
注意 : 无 |
思路 :BFS求得是否存在最小生成树 Prim 中额外加入判断生成树是否唯一 f 记录可选择的同长路径节点 判断这些节点间的距离是否都大与连向他们的距离 并且每一节点仅被已出现的一个节点连接 |
C/C++
box[a] -> 节点 a '直接连接的所有通路'
apr -> appear
#include<bits/stdc++.h>
using namespace std;
long road[501][501];
vector<int> box[501];
bool apr[501];
void BFS(int now);
pair<long,bool>Prim(int N);
int main()
{
memset(road,0x6f,sizeof road);
int N,M,flag=0,a,b,c;
cin >> N >> M;
while (M--){
cin >> a >> b >> c;
box[a].push_back(b);
box[b].push_back(a);
road[a][b] = road[b][a] = c;
// cout << road[a][b] << " " << road[b][a] << endl;
}
for(int z=1;z<=N;z++) if(!apr[z]) {
flag++;
BFS(z);
}
if(flag>1) cout << "No MST" << endl << flag << endl;
else
{
pair<long,bool> x = Prim(N);
cout << x.first << endl << (x.second?"Yes":"No");
}
return 0;
}
void BFS(int now){
if(apr[now]) return;
apr[now] = true;
for(int x:box[now]) BFS(x);
}
pair<long,bool>Prim(int N){
long ed[501];
memset(apr,0,sizeof apr);
memset(ed,0x6f,sizeof ed);
bool flag = true;
long sum = ed[1] = 0,f[501],len=0;
vector<int> ops;
for(int z=1;z<=N;z++){
int op = -1;
for(int z1=1;z1<=N;z1++){
if(!apr[z1]){
if(op==-1 || ed[z1]<ed[op]) op=z1,len=0;
if(op==-1 || ed[z1]<=ed[op]) f[len++] = z1;
}
}
if(flag) {
for(int z1=0;z1<len;z1++) {
int num = 0;
for(int z2:ops) if(road[z2][f[z1]]==ed[op] && apr[z2]) num++;
if(num>1) flag = false;
for(int z2=z1+1;z2<len;z2++){
if(road[f[z1]][f[z2]]<=ed[op]) flag = false;
if(!flag) break;
}
}
}
apr[op] = true;
ops.push_back(op);
sum += ed[op];
for(int z1=1;z1<=N;z1++) ed[z1] = min(ed[z1],road[op][z1]);
}
return {sum,flag};
}