最小生成树(kruskal&prim)畅通工程

畅通工程

Problem Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。

Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。

Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。

Sample Input
  
  
3 3 1 2 1 1 3 2 2 3 4 1 3 2 3 2 0 100

Sample Output
  
  
3 ?

思路:kruskal算法的思想就是:首先将所有的边从小到大排序。然后从最小边开始,找最小边的两顶点的根节点,看是否相同,如果相同连接他们会形成回路,不相同就可以将这两点连接,并记录加入的点的个数。依次往后找,到加入的点和给的点相同时就结束。如果到边查找完后,点的个数不够就说明图是不连通的。



#include"stdio.h"

#include"string.h"
#include"stdlib.h"
int N,M;                    //M villages and N roads
typedef struct 
{
    int v1,v2;
    int len;
}edgetype;
int parents[5050],sum;
int getroot(int v)       //获取顶点v的根节点 
{
    int i;
    i=v;
    while(parents[i]!=i)
    i=parents[i];
    return i;
}
int comp(const void *a,const void *b)   //quickSort中的比较函数 
{
     return (*(edgetype *)a).len - (*(edgetype *)b).len;
}


int join(edgetype em)    //找到目前未并入树中的最小边的两顶点,从这两顶点开始找自己的根节点,如果两个顶点的根节点不同,则合并两点。 
{
int x,y;
x=getroot(em.v1);           //找顶点v1的根节点 
y=getroot(em.v2);           // 找顶点v2的根节点
if(x!=y)                     //如果不相同 ,将v1的根节点作为v2的子树合并到v2的根节点下 
{
parents[x]=y;
++sum;            //并入到树中的节点加1 
return em.len;           //返回目前可以并入到树中的边的长度 
}
return 0;
}


int  kruskal(edgetype em[],int e,int n)
{
    int i,j,k,m,short1,p1,p2,sum1,temp;  //sum1记录最小生成树的长度 
    for(i=1;i<=n;i++)             //将每个节点的父亲节点设为自己 
     parents[i]=i;
     m=1;
     sum1=0;
     temp=0;
     qsort(em,e,sizeof(edgetype),comp); //快排将所有的边从小到大排序 
     for(i=0;i<e;++i)    
     {
      sum1+=join(em[i]);
      if(sum==n)
      return sum1;
     }
     if(sum<n)
      return -1;
     
   
}
int main()
{
    edgetype em[5050];
    int i,j,price,X,Y;
    while(scanf("%d %d",&N,&M)!=EOF&&N)
    {    sum=1;
        for(i=0;i<N;i++)
              {
              scanf("%d %d %d",&X,&Y,&price);
              em[i].v1=X;
              em[i].v2=Y;
              em[i].len=price;
             }
             int ans=kruskal(em,N,M);
             if(ans==-1)
        {
            printf("?\n");
        }
          else
  printf("%d\n",ans); 
    }
    return 0;

}


PRIM算法:从给的节点u开始找与u相连的节点中最短的边,并将这个节点并入到树中,然后调整候选边集

#include"stdio.h"
typedef struct
{
int end;
int len;
}minedge;
typedef struct
{
int edges[101][101];
int n,e;
}graph;


void prim(graph g,int u)
{
int i,j,k,min1,x,v,sum=0; 
minedge min[5050];
//构造候选边集 
for(v=1;v<=g.n;v++)
 {
  min[v].len=g.edges[v][u];
  min[v].end=u;
   }
   min[u].len=0;
   for(i=1;i<g.n;i++) //找到n-1条符合的最小边 
   {
       //find  one short edge 
       min1=100000;
       x=0;
for(j=1;j<=g.n;j++)
{
if(min[j].len>0&&min1>min[j].len)
 {
 min1=min[j].len;
 x=j;
 }

if(min1==100000)
{
printf("?\n");
return ;
   }
sum+=min1;
min[x].len=-min[x].len;
for(k=1;k<=g.n;k++)
{
if(g.edges[k][x]>0&&g.edges[k][x]<min[k].len)
{
min[k].len=g.edges[k][x];
min[k].end=x;
}

   }
   printf("%d\n",sum);
}
int main()
{
graph g;
int i,j,x,y,z,a,b;
while(scanf("%d %d",&a,&b)!=EOF)
{
g.e=a;
g.n=b;
if(g.e==0)
break;
for(i=0;i<101;i++)
 for(j=0;j<101;j++)
    {
g.edges[i][j]=100000;
if(i==j)
g.edges[i][j]=0;
}
for(i=1;i<=g.e;i++)
        {
  scanf("%d %d %d",&x,&y,&z);
  g.edges[x][y]=z;
  g.edges[y][x]=z;
  }
  prim(g,1);
}
return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值