最小生成树的prim算法,思想就是先指定一个点进入点集A(A为已处理过的点的集合),以改点为起点,扫描和该点连接的路径,取最小值计入总路径长度sum,并把该路径的另一点并入A,再以这点为起点扫描……最后得到的sum即为结果
prim的邻接阵代码:
#include <stdio.h> #include <string.h> #define size 105 #define INIT 999999 int count; int Graph[size][size]; long sum; void Prim(int villige) { int i,j; int min,locate; int dist[size]; sum=0; bool visited[size]; memset(visited,0,sizeof(visited)); memset(dist,INIT,sizeof(dist)); for(i=1;i<=villige;i++) //默认第一个点已经进入集合 dist[i] = Graph[1][i]; count = 1; for (j=2;j<=villige;j++) { min = INIT; //找到距离已标记集合最近的点 for(i=2;i<=villige;i++) { if (!visited[i]&&dist[i]<min) //存在未标记的点,min的值才会改变 { min = dist[i]; locate = i; } } if(min!=INIT) //如果min值改变 { visited[locate] = true; sum+=min; count++; //dist[]的更新 for (i=1;i<=villige;i++) {//已经标记过的点,还有自身不用考虑,然后把集合外的点到集合的最小距离存入dist[] if(!visited[i]&&Graph[locate][i]!=0&&dist[i]>Graph[locate][i]) dist[i] = Graph[locate][i]; } } else return ; } } int main() { int road,villige; int i,j,weight; while (scanf("%d%d",&road,&villige)!=EOF&&road) { count = 0; for(i=0;i<=villige;i++) { for(j=0;j<=villige;j++) if(i==j) Graph[i][j] = 0; else Graph[i][j] = INIT; } while (road--) { scanf("%d%d%d",&i,&j,&weight); Graph[i][j] = weight; Graph[j][i] = weight; } Prim(villige); if(count==villige) printf("%ld/n",sum); else printf("?/n"); } return 0; }prim的邻接表代码:
#include<cstdio> #include<cstring> #include<climits> const int N = 205; struct Edge{ int s,e,v; int next; }edge[N]; int e_num,n,m,head[N],vis[N],dist[N]; void AddEdge(int a,int b,int c){ edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c; edge[e_num].next=head[a]; head[a]=e_num++; edge[e_num].s=b; edge[e_num].e=a; edge[e_num].v=c; edge[e_num].next=head[b]; head[b]=e_num++; } void getmap(){ int a,b,c; e_num=0; memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); while(m--){ scanf("%d%d%d",&a,&b,&c); AddEdge(a,b,c); } } void prim(){ int i,j,cur; for(i=1;i<=n;dist[i++]=INT_MAX); for(i=head[1];i!=-1;i=edge[i].next) dist[edge[i].e]=(edge[i].v<dist[edge[i].e]?edge[i].v:dist[edge[i].e]); vis[1]=1; int sum=0; int count=1; for(i=2;i<=n;i++){ int min=INT_MAX; for(j=1;j<=n;j++){ if(!vis[j] && dist[j]<min){ min=dist[j]; cur=j; } } if(min==INT_MAX)break; sum+=min; vis[cur]=1; count++; if(count==n)break; for(j=head[cur];j!=-1;j=edge[j].next){ int u=edge[j].e; if(!vis[u] && dist[u]>edge[j].v) dist[u]=edge[j].v; } } count<n?printf("?\n"):printf("%d\n",sum); } int main() { while(scanf("%d%d",&m,&n),m)//m条路径,n个点 { getmap(); prim(); } return 0; }
kruskal算法就是并查集思想。把所有路径按权值排升序,依次取不使当前图产生回路的边,直到所有点并入集合
代码:
# include<stdio.h> # include<string.h> #include<stdlib.h> int father[101]; struct node { int from,to; int len; }path[5001]; int cmp(const void *a,const void *b) { struct node *aa=(struct node *)a; struct node *bb=(struct node *)b; return aa->len - bb->len; } int findfather(int x) { if(father[x]!=x) father[x]=findfather(father[x]); return father[x]; } void init() { int i; for(i=1;i<=100;i++) father[i]=i; } void merge(int a,int b) { int x,y; x=findfather(a); y=findfather(b); if(x!=y)father[y]=x; } int main() { int i,n,m,s,cnt; while(scanf("%d%d",&n,&m),n) { init(); for(i=0;i<n;i++) scanf("%d%d%d",&path[i].from,&path[i].to,&path[i].len); qsort(path,n,sizeof(path[0]),cmp); for(s=0,i=0;i<n;i++) { if( findfather(path[i].from) != findfather(path[i].to) ) { merge(path[i].from,path[i].to); s+=path[i].len; } } for(i=1;i<=m;i++) father[i]=findfather(i); for(cnt=0,i=1;i<=m;i++) { if(father[i]==i) cnt++; } if(cnt>1) printf("?\n"); else printf("%d\n",s); } return 0; }