很明显,这是一道 最小生成树的例子。也就是,从图中选取若干条边将所有顶点连接起来,并且所选取的这些边的权值之和最小。
算法:Prim算法,或者 Kruskal算法
Prim算法: 首先选择一个点为起点,然后找到与该边相邻权值最小的边,选中该边上的另一个点,然后选择 与选中点 相连接的最小边,这样循环下去,直到包含所有节点
用d[i]表示 与 i 点相邻的最短边的权值,这点是与 Dijkstra算法唯一的不同点
#include <iostream> using namespace std; #define MAXV 30 #define MAX 1<<29 int n; int map[MAXV][MAXV]; int d[MAXV]; bool vis[MAXV]; void prim(){ int i,j; int k = 0; for(i=0;i<n;i++){ vis[i] = 0; d[i] = map[0][i]; } for(i=1;i<=n;i++){ int temp = MAX; for(j=0;j<n;j++){ if(!vis[j]&&d[j]<temp){ temp = d[j]; k = j; } } vis[k] = 1; for(j=0;j<n;j++){ if(!vis[j]&&d[j]>map[k][j]) d[j] = map[k][j]; } } for(i=0;i<n;i++) d[0] += d[i]; cout<<d[0]<<endl; } int main(){ int i,j,num,weight; char a[2],b[2]; while(cin>>n,n){ for(i=0;i<=n;i++) for(j=0;j<=n;j++) if(i == j) map[i][j] = 0; else map[i][j] = MAX; for(i=1;i<n;i++){ cin>>a>>num; for(j=1;j<=num;j++){ cin>>b>>weight; map[a[0]-'A'][b[0]-'A'] = map[b[0]-'A'][a[0]-'A'] = weight; } } prim(); } return 0; }
算法思想:
不断地选择图中权值最小的边,前提是 不能构成回路。
#include <iostream> #include <algorithm> using namespace std; #define INF 1<<29 int p[27]; struct pro{ int u; int v; int w; }map[80]; bool cmp(pro a,pro b){ return a.w<b.w; } int find(int a){ return a == p[a]?a:a=find(p[a]); } int main(){ int n; int i,j,num,c; char a[2],b[2]; while(cin>>n,n){ int k = 0; for(i=0;i<27;i++) p[i] = i; for(i=0;i<n-1;i++){ cin>>a>>num; for(j=1;j<=num;j++,k++){ cin>>b>>c; map[k].u = a[0] - 'A'; map[k].v = b[0] - 'A'; map[k].w = c; } } sort(map,map+k,cmp); int ans = 0; for(i=0;i<k;i++){ int x = find(map[i].u); int y = find(map[i].v); if(x!=y){ ans += map[i].w; p[x] = y; } } cout<<ans<<endl; } return 0; }
总结:Prim算法更注重 点的关系;而Kruskal算法更注重 边的关系