- 問題描述
- 求一個連通無向圖的最小生成樹的代價(圖邊權值爲正整數)
- 輸入
- 第一行是一個整數 N (1 <= N <= 20) ,表示有多少個圖需要計算,以下有 N 個圖,第 i 圖的第一行是一個整數 M (1 <= M <= 50) ,表示圖的頂點數,第 i 圖的第 2 行至 1+M 行爲一個 M*M 的二維矩陣,其元素 ai,j 表示圖的 i 頂點和 j 頂點的連接情況,如果 ai ,j = 0,表示 i 頂點和 j 頂點不相連,如果 ai ,j > 0,表示 i 頂點和 j 頂點的連接權值
- 輸出
- 樣例輸入
1
6
0 6 1 5 0 0
6 0 5 0 3 0
1 5 0 5 6 4
5 0 5 0 0 2
0 3 6 0 0 6
0 0 4 2 6 0
- 樣例輸出
15
- Kruskal 算法
- 對於一個 N*N 矩陣,先構造 N 個沒有連接的頂點,按邊權值大小從小到大選擇頂點,連接不同的生成樹,一條邊連接 2 個頂點,那麼這兩個頂點就在同一顆樹上,要保證每次連接的樹都是不同的,直到只剩下一顆樹爲止,假如現有一條邊連接了 A,B 兩個頂點,另一條連接了 B,C 頂點,那麼 A,B,C在同一顆樹上, A,C 不能再被邊連接,同樣, C 頂點連接的其他頂點也不能和 A 相連,那麼如何做出這樣的判斷呢?
- 算法設計
- 對邊權值從小到大排序,採用鏈式結構,每個節點存儲邊連接的左右端點
- 判斷邊的加入是否構成了環,如果構成了環,那麼這條邊的加入是不合理的
- 代碼
#include<iostream>
using namespace std;
struct Node
{
int l;
int r;
int len;
Node *next;
};
void insert(Node *&head,Node *p);
int main()
{
Node *head,*p;
int n,m,x,temp;
int *a;
int i,j;
int sum;
cin>>n;
while(n--)
{
sum = 0;
cin>>m;
a = new int[m+1];
for (i = 1; i <= m; i++)
{
a[i] = i; //各端點自爲一組
}
head = new Node;
p = head;
p->next = NULL;
for (i = 1; i <= m; i++)
for (j = 1; j <= m; j++)
{
cin>>x;
if (i > j && x != 0) //對稱矩陣
{
p=new Node;
p->l = i;
p->r = j;
p->len = x;
p->next = NULL;
insert(head,p);
}
}
p = head->next;
while (p)
{
if (a[p->l] != a[p->r]) //判斷是否爲同一組
{
sum += p->len;
temp = a[p->l]; //記錄左端點
for(i = 1; i <= m; i++)
if (a[i] == temp) //找到原左端點的值
{
a[i] = a[p->r]; //將左端點的值改爲和右端點一致
}
}
p = p->next;
}
cout<<sum<<endl;
}
return 0;
}
void insert(Node *&head,Node *p)
{
Node *q = head;
while(q->next && q->next->len <= p->len) //從頭結點開始,大的放後面
{
q = q->next;
}
p->next = q->next;
q->next = p;
}