畅通工程
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
3 3 1 2 1 1 3 2 2 3 4 1 3 2 3 2 0 100
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;
}