|
Posted on 2009-08-28 09:12 reiks 阅读(504) 评论(0) 编辑 收藏 引用 所属分类: 算法与数据结构
// PRIM(简单版) 最小生成树算法 (Minimum Spanning Tree) // 输入:图g; // 有向图或者无向图 // 输出:(1)最小生成树长sum; // (2)最小生成树prev。 // 结构: 图g用邻接矩阵表示,最短边长dist用数组表示。 // 算法:Prim算法 //复杂度:O(|V|^2) #include <iostream> #include <vector> #include <list> #include <iterator> #include <algorithm> #include <numeric> #include <functional> #include <climits> using namespace std;
int n; // n : 顶点个数 vector<vector<int> > g; // g : 图(graph)(用邻接矩阵(adjacent matrix)表示) vector<bool> known; // known : 各点是否已经选取 vector<int> dist; // dist : 已选取点集到未选取点的最小边长 vector<int> prev; // prev : 最小生成树中各点的前一顶点 int s; // s : 起点(start) int sum; // sum : 最小生成树长
bool Prim() // 贪心算法(Greedy Algorithm) { known.assign(n, false); dist.assign(n, INT_MAX); prev.resize(n); // 初始化known、dist、prev。 dist[s] = 0; // 初始化起点到自身的路径长为0。 int i; for (i = 0; i < n; ++i) { int min = INT_MAX, v; for (int i = 0; i < n; ++i) if (!known[i] && min > dist[i]) min = dist[i], v = i; // 寻找未知的最短路径长的顶点v, if (min == INT_MAX) break; // 如果找不到,退出; known[v] = true; // 如果找到,将顶点v设为已知, sum += dist[v]; // 调整最小生成树长 for (int w = 0; w < n; ++w) // 遍历所有v指向的顶点w, if (!known[w] && g[v][w] < INT_MAX && dist[w] > g[v][w]) dist[w] = g[v][w], prev[w] = v; // 调整顶点w的最短路径长dist和最短路径的前一顶点 prev。 } return i == n; // 如果选取顶点个数为n,成功。 }
int main() { n = 7; g.assign(n, vector<int>(n, INT_MAX)); g[0][1] = g[1][0] = 2; g[0][2] = g[2][0] = 4; g[0][3] = g[3][0] = 1; g[1][3] = g[3][1] = 3; g[1][4] = g[4][1] = 10; g[2][3] = g[3][2] = 2; g[2][5] = g[5][2] = 5; g[3][4] = g[4][3] = 7; g[3][5] = g[5][3] = 8; g[3][6] = g[6][3] = 4; g[4][6] = g[6][4] = 6; g[5][6] = g[6][5] = 1; s = 0; // 起点任选 sum = 0; if (Prim()) { cout << sum << endl; for (int i = 1; i < n; ++i) if(i != s) cout << prev[i] << "->" << i << endl; } else { cout << "Some vertex cann't be reached." << endl; } system("pause"); return 0; }
/**//*=============================*/ /**//* Write By LiveStar (2008.07.23) */ #include <stdio.h> //max表示点,边的最大个数 #define max 1000 //wq表示两点的距离为无穷 #define wq 9999 //邻接矩阵存储相应的边的权重 int mix[max][max];
//输入并构造邻接矩阵 void input(int n,int m) { int i,j,sp,ep,wg; //初始化邻接矩阵每个都是无穷大 for (i=0;i<n;i++) for (j=0;j<n;j++) mix[i][j]=wq; printf("请输入边的起点、终点、权重(EX:1 2 3):\n"); for (i=0;i<m;i++) { scanf("%d %d %d",&sp,&ep,&wg); //无向连通图 mix[sp][ep]=wg; mix[ep][sp]=wg; } }
//显示邻接矩阵 void output(int n,int m) { int i,j; printf("\n邻接矩阵如下:\n\n"); for (i=0;i<n;i++) { for (j=0;j<n;j++) printf("%d\t",mix[i][j]); printf("\n"); } }
//prim算法实现 void prim(int n,int r) { //a[max]用来存放各个点到已经标记点的集合的最短距离 int a[max]; //b[max]用来记录每个点的标记状态,false表示还没标记。 bool b[max]; int i,j,k,min; //初始化从根节点开始 for (i=0;i<n;i++) { a[i]=mix[r][i]; b[i]=false; } b[r]=true; printf("\n依次被标记的点及相应边的权重:\n"); printf("%d\t%d\n",r,0); for (i=0;i<n-1;i++)//还剩n-1个点 { k=0; min=wq; for (j=0;j<n;j++) { //第j个点到已经标记点的集合的距离最小且这个点还没有被标记 //k记录下一个将被标记的点 if (a[j]<min&&b[j]==false) { min=a[j]; k=j; } } b[k]=true;//标记节点k printf("%d\t%d\n",k,min); //更新a[]里的状态,时刻保持最新的状态 //存放各个点到已经标记点的集合的最短距离 for (j=0;j<n;j++) { if (mix[k][j]<a[j]) { a[j]=mix[k][j]; } } } }
int main() { //n是点的个数 ,m是边的个数 int n,m,r; printf("请输入点的个数和边的个数(EX:1 3):\n"); scanf("%d %d",&n,&m); //输入并构造邻接矩阵 input(n,m); //显示邻接矩阵 output(n,m); while (1) { printf("\n请输入根节点(-1跳出):\n"); scanf("%d",&r); if(r==-1) break; //prim算法实现 prim(n,r); printf("\n\n"); } return 0; }
|