https://blog.csdn.net/SYaoJun/article/details/101450783?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160733587819725271011092%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=160733587819725271011092&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-3-101450783.pc_search_result_no_baidu_js&utm_term=%E7%95%85%E9%80%9A%E5%B7%A5%E7%A8%8B%E4%B9%8B%E5%B1%80%E9%83%A8%E6%9C%80%E5%B0%8F%E8%8A%B1%E8%B4%B9%E9%97%AE%E9%A2%98&spm=1018.2118.3001.4449
https://www.bilibili.com/video/BV1b7411N798?p=45(讲并查集的)
#include<bits/stdc++.h>
//#include<stdlib.h>
#define MAX 101
#define INFINITY 65535
bool is_mark[MAX];//标记是否合并
int pathmatrirx[MAX][MAX];//所有路径长
int Dist[MAX];//当前连通量与其他地点的最短距离
int main() {
int numofvertex;
scanf("%d", &numofvertex);
memset(pathmatrirx, 0x3f, sizeof(pathmatrirx));//带权图邻接矩阵初始化为无穷大,这里因为输入的边已经把图全塞满了,所有的点之间都有相互的边,所以不初始化为无穷大也可以,反正后面会输入修改
int arcs = numofvertex * (numofvertex - 1) / 2;//所有的边数
//输入边即道路修建成本
for (int i = 0; i < arcs; i++) {
int vil1, vil2, cost, state;
scanf("%d%d%d%d", &vil1, &vil2, &cost, &state);
//如果该道路已修好,则不计成本
if (state == 1) {
pathmatrirx[vil1 - 1][vil2 - 1] = pathmatrirx[vil2 - 1][vil1 - 1] = 0;
}
//否则,记录修建成本
else {
pathmatrirx[vil1 - 1][vil2 - 1] = pathmatrirx[vil2 - 1][vil1 - 1] = cost;
}
}
//初始化Dist表
for (int i = 0; i < numofvertex; i++) {
Dist[i] = pathmatrirx[0][i];
}
//标记第一个点,且第一个点到自身的距离更改为0
is_mark[0] = 0;
// Dist[0] = 0;
int sum = 0;
for (int i = 0; i < numofvertex; i++) {
int minpath = INFINITY;
int order = -1;
for (int j = 1; j < numofvertex; j++)//只记个次数,合并这些次,循环里面并不用i
{
if (minpath > Dist[j] && !is_mark[j]) {
minpath = Dist[j];//选取目前离连通量最小的路径
order = j;//记录离目前连通量最近的点的坐标
}
}
//合并该点(标记该点)
is_mark[order] = true;
//每合并一个点,修改其他点到目前连通量的最小路径
if (order != -1) {
//最小路径求和
sum += minpath;
for (int j = 1; j < numofvertex; j++) {
if (Dist[j] > pathmatrirx[order][j]) {
//如果有点距离当前连通量的距离小于原距离,修改Dist表
Dist[j] = pathmatrirx[order][j];
}
}
}
}
printf("%d\n", sum);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int sum=0;
struct stu{
int e=100000;//花费
int flag=3;//flag无路,不可修建状态
}xx[101][101];
int n;
void fun(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
if(i==j||i==k||j==k) continue;
if(xx[k][j].e>xx[k][i].e+xx[i][j].e)
xx[k][j].e=xx[k][i].e+xx[i][j].e;//各个点之间花费最少
}
}
}
}
int main(){
int a,b,c,d,min;
cin>>n;
for(int i=0;i<n*(n-1)/2;i++){
cin>>a>>b>>c>>d;
xx[a][b].flag=xx[b][a].flag=d;
if(d==0)
xx[a][b].e=xx[b][a].e=c;
else if(d==1) xx[a][b].e=xx[b][a].e=0;
}
//寻找各个点之间最小花费
fun();
int sum=0;
for(int i=2;i<=n;i++){
sum=sum+xx[1][i].e;
xx[1][i].e=0;
fun();//这个解法时间复杂度比较大,
}
cout<<sum;
return 0;
}
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10007;
struct edge{
int u, v, cost, st;//起点,终点,花费,状态
bool operator < (const edge a)const{
return cost < a.cost;
}
}E[N];
int root[N];
int find(int x){
if(root[x] != x)
root[x] = find(root[x]);
return root[x];
}
int main(){
int n;
cin>>n;
for(int i = 1; i <= n; i++){
root[i] = i;
}
int len = n*(n-1)/2;
for(int i = 0; i < len; i++){//先把st=1,已连接的归入一个集,防止后边+花费
cin>>E[i].u>>E[i].v>>E[i].cost>>E[i].st;
if(E[i].st == 1){
// int u = find(E[i].u);
// int v = find(E[i].v);
// if(u != v){
// root[v] = u;//将点归入同一个集
// }
E[i].cost=0;
}
}
sort(E, E+len);
int cost = 0;
for(int i = 0; i < len; i++){ //先连的肯定是花费最小的,每个边都要检查一次,len次
int u = find(E[i].u);
int v = find(E[i].v);
if(u != v){//判断这个边的起点和终点是否在一个集里,如果不是同一个集,即不构成回路,就连上(root归同)
root[v] = u;
cost += E[i].cost;
}
}
cout<<cost<<endl;
return 0;
}
另一个prime,这个比1简练些,其实里面有一些if判断条件应该不用加,不过我没测试
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
int x[101][101];
int val[101];
int mark[101];
int main()
{
int dianshu,m,sum=0;
cin >> dianshu;
m= dianshu * (dianshu - 1) / 2;
for(int i=1;i<=m;i++)
{
int start,end,e,r;
cin >> start >> end >> e >> r;
if(r==1)x[start][end]=0;
else x[start][end]=e;
x[end][start]=x[start][end];//双向图
}
mark[1]=1;//一定从第一个村庄开始,1为连上
for(int i=1; i <= dianshu; i++)
{
val[i]=x[1][i];//距连通量的花费
}
int count=1;
while(count < dianshu)//dianshu-1次
{
int min=INF;
int f=0;
for(int i=1; i <= dianshu; i++)
{
if(mark[i] == 0 && val[i] < min)
{
min=val[i];//最短距离
f=i;
}
}
mark[f]=1;
count++;
sum+=min;
for(int i=1; i <= dianshu; i++)
{
if(mark[i] == 0 && val[i] >= x[f][i])
{
val[i]=x[f][i];//当有更小的权值时才会改变。
}
}
}
cout<<sum<<endl;
return 0;
}