若要在n個城市之間建設通訊網絡,只需要架設n-1條線路即可。如何以最低的經濟代價建設這個通訊網絡,是一個網的最小生成樹問題。本單元的實驗內容主要是利用克魯斯卡爾算法求出網的最小生成樹,并且以文本形式輸出樹中的各條邊以及他們的權值。
#include<iostream>
#include<stdlib.h>//產生隨機數組用
#include<time.h> //同上
?#include<list>
{
public:
??? int m_beginVex;
??? int m_endVex;
??? int m_weight;
??? MyArc(int beginVex,int endVex,int weight);
??? MyArc(){}
??? bool operator < (const MyArc& arc)
??? {
??????? return m_weight<arc.m_weight;
??? }
??? bool operator == (const MyArc& arc)
??? {
??????? return m_weight==arc.m_weight;
??? }
??? bool operator > (const MyArc& arc)
??? {
??????? return m_weight>arc.m_weight;
??? }
}? ;
{}
//2) 表示圖的鄰接矩陣類Graph:
class Graph
{
public:
??? int m_vexnum;
??? int m_arcnum;
??? int *m_pmatrix;
public:
??? ~Graph();
??? Graph(int vexnum);
??? Graph(int vexnum,int *pmatrix);
??? void insert(MyArc arc);//按權值大小排序插入
??? bool bound(int x);?? //判斷頂點x是否已與其它頂點連通
};
//構造函數
Graph::Graph(int vexnum)
{
??? m_pmatrix=new int[vexnum*vexnum];
??? m_vexnum=vexnum;m_arcnum=0;
??? for(int i=0;i<vexnum*vexnum;++i)
??? m_pmatrix[i]=0;
Graph::Graph(int vexnum,int *pmatrix)
{
??? m_vexnum=vexnum;
??? // m_arcnum=arcnum;
??? m_pmatrix=new int[m_vexnum*m_vexnum];
??? for(int i=0;i<m_vexnum*m_vexnum;++i)
??????? m_pmatrix[i]=pmatrix[i];
}
bool Graph::bound(int x)
{
??? for(int i=0;i<m_vexnum;++i) if(m_pmatrix[x+i*m_vexnum]!=0) return true;
??? return false;
}
void Graph::insert(MyArc arc)
{
??? m_pmatrix[arc.m_beginVex*m_vexnum+arc.m_endVex]=arc.m_weight;
??? m_pmatrix[arc.m_endVex*m_vexnum+arc.m_beginVex]=arc.m_weight;
??? ++m_arcnum;
}
//析構
Graph::~Graph()
{
??? delete[] m_pmatrix;
}
//3) 按權存儲邊的有序隊列類MyQueues:
class MyQueues
{
public:
??? list<MyArc> m_list;
??? MyQueues(){}
??? void insert(const MyArc& arc);//邊按權值插入隊列中合適位置,
??? void InsertGraph(const Graph &graph);//將圖的連通分量插入隊列
??? MyArc pop();
};
//邊出隊
MyArc MyQueues::pop()
{
??? MyArc arc=m_list.front();
??? m_list.pop_front();
??? return arc;
}
//邊按權值插入隊列中合適位置,
void MyQueues::insert(const MyArc& arc)
{
??? list<MyArc>::iterator pos;
??? pos=m_list.begin();
??? while(pos!=m_list.end())
??? {
??????? if(*pos>arc) break;
??????? else ++pos;
??? }
??? m_list.insert(pos,arc);
}
//將圖的連通分量插入隊列
void MyQueues::InsertGraph(const Graph &graph)
{
??? for(int i=0;i<graph.m_vexnum;++i)
??? {
??????? for(int j=i+1;j<graph.m_vexnum;++j)
????????????? if(graph.m_pmatrix[i*graph.m_vexnum+j]) insert(MyArc(i,j,graph.m_pmatrix[i*graph.m_vexnum+j]));
??? }
}
bool IsCycle(Graph& graph, MyArc& arc)
{
??? list<int> my_list;
??? my_list.push_back(arc.m_beginVex);
??? int *ps=new int[graph.m_vexnum];
??? for(int i=0;i<graph.m_vexnum;++i)
??????? ps[i]=0;
??? while(!my_list.empty())
??? {
??????? int x=my_list.front();
??????? ps[x]=1;
??????? my_list.pop_front();
??????? for(int i=0;i<graph.m_vexnum;++i)
??????? {
????????????? if(graph.m_pmatrix[i+x*graph.m_vexnum]!=0)
????????????? {
????????????????? if(i==arc.m_endVex) return true;
????????????????? if(ps[i]!=1) my_list.push_back(i);
????????????? }
??????? }
??? }
??? delete[] ps;
??? return false;
}
//4) kruskal算法:
void kruskal(const Graph& graph,Graph& smtree)
{
??? MyQueues arcqueues;//保存從小到大排列的邊
??? arcqueues.InsertGraph(graph);
??? MyArc myarc;//Arc表示邊的類型
??? int arcnum=0; //邊的個數
??? while(arcnum<graph.m_vexnum-1)
??? {
??????? myarc=arcqueues.pop();
??????? if(!IsCycle(smtree,myarc))
??????? {
????????????? smtree.insert(myarc);
????????????? ++arcnum;
??????? }
??? }
}
void SetMatrix(int vexnum,int *pmatrix)
{
??? srand((unsigned)time(NULL));
??? for(int i=0;i<vexnum;++i)//產生隨機權值矩陣
??? {
??????? for(int j=i;j<vexnum;++j)
??????? {
????????????? if(j==i)
????????????? {
????????????????? pmatrix[i*vexnum+j]=0;
????????????????? continue;
????????????? }
????????????? int rnum=rand();rnum%=99;rnum++;//產生1~99的隨機整數作為邊的權值
????????????? pmatrix[i*vexnum+j]=rnum;
????????????? pmatrix[j*vexnum+i]=rnum;
??????? }
??? }
??? cout<<"***隨機產生的各邊權值矩陣 [頂點數為 "<<vexnum<<"] ****\n";
? for(int i=0;i<vexnum;++i)//輸出隨機權值矩陣
??? {
??????? for(int j=0;j<vexnum;++j)
??????? {
????????????? cout<<pmatrix[i*vexnum+j]<<"\t";
??????? }
??????? cout<<endl;
??? }
}
void SmallestTreeOutput(const Graph& smtree)
{
??? cout<<"最小生成樹:"<<endl;
??? for(int i=0;i<smtree.m_vexnum;++i)//輸出最小樹
??????? for(int j=i+1;j<smtree.m_vexnum;++j)
????????????? if(smtree.m_pmatrix[i*smtree.m_vexnum+j])
????????????????? cout<<'('<<i<<','<<j<<','<<smtree.m_pmatrix[i*smtree.m_vexnum+j]<<')'<<endl;
}
?
void main()
{
??? char i;
??? cout<<"請輸入頂點數目:";
??? cin>>i;
? int vex=i-'0';
??? int *matrix=new int[vex*vex];
??? cout<<endl;
??? SetMatrix(vex,matrix);
??? Graph graph(vex,matrix),smtree(vex);
??? kruskal(graph,smtree);
??? SmallestTreeOutput(smtree);
??? delete []matrix;
}
結果輸出:
請輸入頂點數目:6
***隨機產生的各邊權值矩陣 [頂點數為 6] ****
0?????? 64????? 7?????? 15????? 22????? 43
64????? 0?????? 72????? 86????? 53????? 40
7?????? 72????? 0?????? 53????? 37????? 22
15????? 86????? 53????? 0?????? 87????? 82
22????? 53????? 37????? 87????? 0?????? 9
43????? 40????? 22????? 82????? 9?????? 0
最小生成樹:
(0,2,7)
(0,3,15)
(0,4,22)
(1,5,40)
(4,5,9)