hdu 1863 畅通工程(prim算法实现和kruskal算法实现)

来源:互联网 发布:mac route命令 编辑:程序博客网 时间:2024/06/06 05:06

最小生成树的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;}