const int n=6; //圖的頂點數
const int e=10; //圖的邊數 n-1=<e<=n(n-1)/2
typedef int adjmatrix[n][n];
typedef struct{ //生成樹的邊結點
int fromvex,endvex; //邊的起點與終點
int weight; //邊上的權
}TreeEdgeNode;
typedef TreeEdgeNode edgesetT[n-1]; //這是不
typedef TreeEdgeNode edgesetG[e];
void Kruskal(edgesetG GE,edgesetT CT,int n)
//利用克魯斯卡爾算法求邊集數組GE所示圖的最小生成樹,
//樹中每條邊依次存於數組C中
{
int i,j;
adjmatrix s;//用二維數組s作爲集合使用,其中每一行元素
//s[i][0]~s[i][n-1]用來表示一個集合,若s[i][t]==1
//則表示v[t]頂點屬於該集合,否則不屬於s[i]集合
for(i=0;i<n;i++)
{ //初始化s集合,使每一個頂點分屬於不同的集合
for(j=0;j<n;j++)
if(i==j)
s[i][j]=1;
else
s[i][j]=0;
}//循環執行結束後,使得v[i]頂點屬於s[i]集合中
int k=1;//k表示待獲取的最小生成樹中的邊數,初值爲1
int d=0;//d表示GE中待掃描邊元素的下標位置,初值爲0
int m1,m2;//m1和m2用來分別記錄一條邊的兩個頂點所在的集合的序號
while(k<n)
{//進行n-1次循環,得到最小生成樹中的n-1條邊
/*for(i=0;i<n;i++)
{//求出邊GE[d]的兩個頂點所在集合的序號m1和m2]
for(j=0;j<n;j++)
{
if(GE[d].fromvex==j&&s[i][j]==1)//找起點
m1=i;
if(GE[d].endvex==j&&s[i][j]==1)//找終點
m2=i;
}
}*/
//可以把上面的重for循環改良成如下的一重for循環
for(i=0;i<n;i++)
{
if(s[i][GE[d].fromvex]==1)//找起點
m1=i;
if(s[i][GE[d].endvex]==1)//找終點
m2=i;
}
if(m1!=m2)
{ //若兩集合序號不等,則表明GE[d]是生成樹中的一條邊,
//應將它加入到數組C中
CT[k-1]=GE[d];
//cout<<"CT[<<k-1<<]=<<CT[k-1].
k++;
for(j=0;j<n;j++)
{//合併兩個集合,並將另一個置爲空集
s[m1][j]=s[m1][j]||s[m2][j];
s[m2][j]=0;
}
}
d++;//d後移一個位置,以便掃描GE中的下一條邊
}
}
void main()
{
int i;
edgesetG GE;
edgesetT CT;
cout<<"請按權值小到大輸入邊集:"<<endl;
for(i=0;i<e;i++)//這是不妥的,因爲不知道到底有多少邊
{
cin>>GE[i].fromvex>>GE[i].endvex>>GE[i].weight;
}
Kruskal(GE,CT,n);
cout<<"最上生成樹的邊集爲:"<<endl;
for(i=0;i<n-1;i++)
{
cout<<CT[i].fromvex<<" "<<CT[i].endvex<<" "<<CT[i].weight<<endl;
}
}
/*測試用例一:
請按權值小到大輸入邊集:
0 4 4
1 2 5
1 3 8
2 3 10
1 5 12
3 5 15
0 1 18
3 4 20
0 5 23
4 5 25
最上生成樹的邊集爲:
0 4 4
1 2 5
1 3 8
1 5 12
0 1 18
*/