算法競賽中常用的算法,求圖的最小生成樹
過程:
對邊集排序,
選取最小邊,將連接的節點放到一個集合中
選取次小的邊,當邊連接的定點不在同一個集合中時,合併集合。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int u[200],v[200];//最大有200條邊,每條邊的兩個節點的位置
float w[200];//每條邊的權值
int f[200];//200個邊的父節點,並查集使用
int node_num,side_num;//節點個數,邊的個數
int r[200];//儲存排序後,第小的邊的編號
queue<int> side;
void build_map()//建立圖
{
int i;
i = 0;
printf("輸入節點個數:\n");
scanf("%d", &node_num);//輸入節點個數
printf("輸入邊的信息:節點1,節點2,權重 \n");
while(1)
{
int a, b;
float c;
if (scanf("%d,%d,%f", &a, &b, &c) != 3) break;//輸入該邊的兩個定點以及該邊的權重
u[i] = a;
v[i] = b;
w[i] = c;
i++;
}
side_num = i;//統計邊的個數
}
int cmp(int i, int j)
{
return w[i] < w[j];
}
int find(int x)
//並查集,用於判斷是否在同一個集合
//這是這些天遇到的第二個暴力,簡潔,優美的算法了
{
return f[x] == x ? x : find(f[x]);
}
int main()
{
build_map();
for (int i = 0; i < node_num; i++)
{
f[i] = i;//初始化並查集
}
for (int i = 0; i < side_num; i++)
{
r[i] = i;//初始化邊的編號
}
sort(r, r + side_num, cmp);//對邊按照順序排列
for (int i = 0; i < side_num; i++)
{
int k = r[i];
int x = find(u[k]);
int y = find(v[k]);
if (x != y)//若兩個節點不在同一個集合裏,則合併
{
f[x] = y;
side.push(r[i]);
}
}
printf("邊集爲:\n");
while (!side.empty())//輸出邊集
{
int m = side.front();
side.pop();
printf("%d,%d\n", u[m], v[m]);
}
return 0;
}