普利姆最小生成树算法:
/* 时间:2017.1.1 描述:普利姆算法求解最小生成树 */ #include<iostream> #include<climits> #include<cstdio> #include<iomanip> #include<cstring> #include<fstream> #define INF INT_MAX #define FILEINPUT 1 using namespace std; typedef struct edgeNode { int from,to; int cost; } EDGENODE; void creatMatrix(int **AdjMatrix,int n,int e); //构建无向图的邻接矩阵 void printMatrix(int **AdjMatrix,int n); //输出图的邻接矩阵 void initEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int start); //初始化边集 int chooseEdge(EDGENODE *edgeSet,int n,int index); //从候选边集中选取权重最小的边 void modfiyEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int index,int to);//调整候选边集 void primMst(int **AdjMatrix,EDGENODE *edgeSet,int n,int start); //普利姆算法 void printMst(EDGENODE *edgeSet,int n); //输出最小生成树选举结果 int main() { //freopen("data.txt","r",stdin); #if FILEINPUT //条件编译:输入重定向到文件(输入邻接矩阵数据) ifstream fin("data.txt"); streambuf *strm_buf=cin.rdbuf(); cin.rdbuf(fin.rdbuf()); #endif int i,n,e,start; int **AdjMatrix; //存储邻接矩阵 EDGENODE *edgeSet; //存储最小生成树选的边集 cout<<"Enter the number of nodes and edges:"<<endl; cin>>n>>e; AdjMatrix=(int **)malloc(sizeof(int *)*n); //为邻接矩阵分配存储空间 for(i=0;i<n;i++) AdjMatrix[i]=(int *)malloc(sizeof(int)*n); edgeSet=(EDGENODE *)malloc(sizeof(EDGENODE)*n); //为最小生成树边集合配存储空间 creatMatrix(AdjMatrix,n,e); //构建无向图的邻接矩阵 printMatrix(AdjMatrix,n); //输出图的邻接矩阵 #if FILEINPUT //条件编译:输入重定向到键盘(输入普利姆算法的起始顶点) cin.rdbuf(strm_buf); #endif while(1) { cout<<"Enter the start position of the Graph: "; cin>>start; primMst(AdjMatrix,edgeSet,n,start); printMst(edgeSet,n); } #if FILEINPUT //条件编译:输入重定向到键盘(输入普利姆算法的起始顶点) fin.close(); #endif return 0; } void creatMatrix(int **AdjMatrix,int n,int e) { int i,j,from,to,cost; for(i=0;i<n;i++) for(j=0;j<n;j++) AdjMatrix[i][j]=INF; cout<<"<from----to----cost>"<<endl; for(i=0;i<e;i++) { cin>>from>>to>>cost; AdjMatrix[from][to]=cost; AdjMatrix[to][from]=cost; } } void printMatrix(int **AdjMatrix,int n) { int i,j; for(i=0;i<n;i++) { for(j=0;j<n;j++) if(AdjMatrix[i][j]==INF) cout<<setiosflags(ios::left)<<setw(6)<<"INF"; else cout<<setiosflags(ios::left)<<setw(6)<<AdjMatrix[i][j]; cout<<endl; } } void initEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int start) { int i,index=0; for(i=0;i<n;i++) if(i!=start) { edgeSet[index].from=start; edgeSet[index].to=i; edgeSet[index].cost=AdjMatrix[start][i]; index++; } } int chooseEdge(EDGENODE *edgeSet,int n,int index) { int minCost=INF,minPos,i; for(i=index;i<n-1;i++) if(edgeSet[i].cost<minCost) { minCost=edgeSet[i].cost; minPos=i; } if(minCost==INF) { cout<<"The Graph is disconnected!"<<endl; exit(1);//图不连通,程序结束 } return minPos; } void modfiyEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int index,int to) { int i,cost; for(i=index;i<n-1;i++) { cost=AdjMatrix[to][edgeSet[i].to]; if(cost<edgeSet[i].cost) { edgeSet[i].cost=cost; edgeSet[i].from=to; } } } void primMst(int **AdjMatrix,EDGENODE *edgeSet,int n,int start) { int iter,minPos,to; EDGENODE edge; initEdgeSet(AdjMatrix,edgeSet,n,start); //初始化边集合 for(iter=0;iter<n-1;iter++) { minPos=chooseEdge(edgeSet,n,iter); //从边集中选择取值最小边 edge=edgeSet[minPos]; //将选择的最小边edgeSet[iter] edgeSet[minPos]=edgeSet[iter]; edgeSet[iter]=edge; to=edgeSet[iter].to; //将选择的边结点加入U集合 modfiyEdgeSet(AdjMatrix,edgeSet,n,iter,to);//调整候选边结点 } } void printMst(EDGENODE *edgeSet,int n) { int index; int totalCost=0; for(index=0;index<n-1;index++) { cout<<"("<<edgeSet[index].from<<","<<edgeSet[index].to<<") "<<edgeSet[index].cost<<endl; totalCost+=edgeSet[index].cost; } cout<<"totalCost: "<<totalCost<<endl; } 克鲁斯科尔算法的测试数据:第一行表示图的顶点数和边数;从第二行开始表示表的顶点编号和权值 10 13 0 1 4 1 2 2 0 3 3 3 4 8 1 5 2 2 5 2 4 5 1 3 6 10 4 7 4 5 8 4 7 8 6 6 9 5 7 9 2克鲁萨卡尔算法:
/* 时间:2017.1.1 描述:结合并查集实现克鲁斯卡尔算法求最小生成树 */ #include<iostream> #include<climits> #include<iomanip> #include<cstring> #include<fstream> #include<algorithm> #define INF INT_MAX #define FILEINPUT 1 using namespace std; typedef struct edgeNode { int from,to; int cost; } EDGENODE; bool operator<(const EDGENODE &a,const EDGENODE &b) { if(a.cost!=b.cost) return a.cost<b.cost; else if(a.from!=b.from) return a.from<b.from; else return a.to<b.to; } int flag[512]; void creatMatrix(int **AdjMatrix,EDGENODE *edgeSet,int n,int e); void printMatrix(int **AdjMatrix,int n); void printEdgeSet(EDGENODE *edgeSet,int e); void kruskalMst(EDGENODE *edgeSet,int n,int e); int findRootEdge(int nodeNumber); int mergeEdge(int nodeFrom,int nodeTo); int main() { //freopen("data.txt","r",stdin); #if FILEINPUT //条件编译:输入重定向到文件(输入邻接矩阵数据) ifstream fin("data.txt"); streambuf *strm_buf=cin.rdbuf(); cin.rdbuf(fin.rdbuf()); #endif int i,n,e; int **AdjMatrix; //存储邻接矩阵 EDGENODE *edgeSet; //边集合 cout<<"Enter the number of nodes and edges:"<<endl; cin>>n>>e; AdjMatrix=(int **)malloc(sizeof(int *)*n); //为邻接矩阵分配存储空间 for(i=0;i<n;i++) AdjMatrix[i]=(int *)malloc(sizeof(int)*n); edgeSet=(EDGENODE *)malloc(sizeof(EDGENODE)*e); //为边集合分配存储空间 for(i=0;i<n;i++) //初始化并查集 flag[i]=i; creatMatrix(AdjMatrix,edgeSet,n,e); printMatrix(AdjMatrix,n); kruskalMst(edgeSet,n,e); #if FILEINPUT //条件编译:输入重定向到键盘(输入普利姆算法的起始顶点) cin.rdbuf(strm_buf); fin.close(); #endif return 0; } void creatMatrix(int **AdjMatrix,EDGENODE *edgeSet,int n,int e) { int i,j,from,to,cost; EDGENODE edge; for(i=0;i<n;i++) for(j=0;j<n;j++) AdjMatrix[i][j]=INF; cout<<"<from----to----cost>"<<endl; for(i=0;i<e;i++) { cin>>from>>to>>cost; AdjMatrix[from][to]=cost; AdjMatrix[to][from]=cost; edge.from=from; edge.to=to; edge.cost=cost; edgeSet[i]=edge; } } void printMatrix(int **AdjMatrix,int n) { int i,j; for(i=0;i<n;i++) { for(j=0;j<n;j++) { if(AdjMatrix[i][j]==INF) cout<<setiosflags(ios::left)<<setw(6)<<"INF"; else cout<<setiosflags(ios::left)<<setw(6)<<AdjMatrix[i][j]; } cout<<endl; } } void printEdgeSet(EDGENODE *edgeSet,int e) { int index=0; for(index=0;index<e;index++) cout<<"("<<edgeSet[index].from<<","<<edgeSet[index].to<<") "<<edgeSet[index].cost<<endl; } int findRootEdge(int nodeNumber) { int i,j,root; root=nodeNumber; while (flag[root]!=root) //循环结束,则找到同一边集中的最小结点编号 root= flag[root]; i=nodeNumber; while(i!=root) //本循环修改查找路径中所有边结点编号 { j=flag[i]; flag[i]=root; i=j; } return root; } int mergeEdge(int nodeFrom,int nodeTo) //边结点合并到连通图中 { int indexFrom=findRootEdge(nodeFrom); int indexTo=findRootEdge(nodeTo); if(flag[indexFrom]<flag[indexTo]) flag[indexTo]=indexFrom; else flag[indexFrom]=indexTo; if(indexFrom==indexTo) return 1; else return 0; } void kruskalMst(EDGENODE *edgeSet,int n,int e) { int index=0; int countEdge=0; int minCost=0; //cout<<"------------------------------------"<<endl; //printEdgeSet(edgeSet,e); sort(edgeSet,edgeSet+e); //对边集进行快速排序 //cout<<"------------------------------------"<<endl; //printEdgeSet(edgeSet,e); //cout<<"------------------------------------"<<endl; while(index<e) { int from=edgeSet[index].from; int to=edgeSet[index].to; int cost=edgeSet[index].cost; if(mergeEdge(from,to)==0) //利用并查集判断环路,同时对查找路径进行压缩合并 { countEdge++; minCost+=cost; cout<<"("<<from<<","<<to<<") "<<cost<<endl; index++; } else { index++; } if(countEdge==n-1) { break; } } if(index<e) cout<<"minCost: "<<minCost<<endl; else { cout<<"The Graph is disconnected!"<<endl; //index>=e则不能构造最小生成树 } }