牛客网题目链接
并查集+kruskal算法
解题思路
把已经修建的公路先求出最小生成树,然后从未修建的公路中用kruskal算法算出最短的边,加入生成树中。
注意
1.已经修建好的路需要先连通起来
2.边的数量接近是点数量的平方级别,所以数组开大点
3.如果所有点都连通了,可以提前退出
版本1
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <cctype>
#include <unordered_map>
#include <map>
using namespace std;
const int N = 5005;
typedef pair<int, string> PII;
int root[N];
int find(int x){
if(x != root[x]) root[x] = find(root[x]);
return root[x];
}
struct road{
int u, v, w, s;
bool operator < (const road a)const{
return w < a.w;
}
}E[N];
int main() {
int n;
while(cin>>n){
if(!n) break;
int m = n*(n-1)/2;
for(int i = 1; i <= n; i++){
root[i] = i;
}
int cnt = 1, w = 0, st;
for(int i = 0; i < m; i++){
cin>>E[i].u>>E[i].v>>E[i].w>>E[i].s;
if(E[i].s){
int a = find(E[i].u);
int b = find(E[i].v);
if(a != b){
root[b] = a;
cnt++;
}
}
}
sort(E, E + m);
for(int i = 0; i < m; i++){
if(!E[i].s){
int a = find(E[i].u);
int b = find(E[i].v);
if(a != b){
root[b] = a;
w += E[i].w;
cnt++;
}
}
if(cnt == n) break;
}
cout<<w<<endl;
}
return 0;
}
版本2
#include<cstdio>
#include<algorithm>
#define N 5000
using namespace std;
int father[N];
struct edge{
int u,v;
int cost;
bool operator <(const edge &b)const{
return cost < b.cost;
}
}E[N],T[N];
int find(int x){
if(x == father[x]) return x;
else{
int tp = find(father[x]);
father[x] = tp;
return tp;
}
}
int main(){
int n,x,y,w,p;
while(scanf("%d",&n)!=EOF&& n != 0){
int k=0,l=0;
for(int i=1;i <= (n-1)*n/2; i++){
scanf("%d%d%d%d",&x,&y,&w,&p);
if(p==1){ //已经修好了
E[k].u = x;
E[k].v = y;
E[k].cost = w;
k++;
}else if(p ==0){
T[l].u = x;
T[l].v = y;
T[l].cost = w;
l++;
}
}
int ans = 0;
for(int i=1;i<=n;i++){
father[i] = i;
}
sort(T,T+l);
sort(E,E+k);
for(int i=0;i<k;i++){
int faU = find(E[i].u);
int faV = find(E[i].v);
if(faU != faV){
father[faU] =faV;
}
}
for(int i=0;i<l;i++){
int faU = find(T[i].u);
int faV = find(T[i].v);
if(faU != faV){
father[faU] =faV;
ans += T[i].cost;
}
}
printf("%d\n",ans);
}
return 0;
}