Kruskal算法例题

例题一:剑鱼行动(Swordfish).

题目描述:给定平面上N个城市的坐标,计算连接这n个城市所需线路长度的最小值。

输出描述:如下图所示,每两个测试数据的输出之间输出一个空行

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<stdlib.h>
using namespace std;
#define MAXN 110
#define MAXM 5000
struct edge
{
    int u,v;
    double w;
}edges[MAXN];
int parent[MAXN];
int n,m;
double x[MAXN],y[MAXN];///每个顶点x坐标和y坐标
int i,j;
double sumweight;
void UFset()
{
    for(i=0;i<n;i++)
        parent[i]=-1;
}
int Find(int x)
{
    int s;
    for(s=x;parent[s]>=0;s=parent[s]);
    while(s!=x)///压缩路径
    {
        int temp=parent[x];
        parent[x]=s;
        x=temp;
    }
    return s;
}
void Union(int R1,int R2)
{
   int r1=Find(R1);
   int r2=Find(R2);
   int temp=parent[r1]+parent[r2];
   if(parent[r1]>parent[r2])///加权法则
   {
       parent[r1]=r2;
       parent[r2]=temp;
   }
   else
   {
       parent[r2]=r1;
       parent[r1]=temp;
   }
 }
 int cmp(const void *a,const void *b)
 {
     edge aa=*(const edge *)a;
     edge bb=*(const edge *)b;
     if(aa.w>bb.w) return 1;
     else
        return -1;
 }
 void Kruskal()
 {
     int num=0;
     int u,v;
     UFset();
     for(i=0;i<m;i++)
     {
         u=edges[i].u;
         v=edges[i].v;
         if(Find(u)!=Find(v))
         {
             sumweight+=edges[i].w;
             num++;
             Union(u,v);
         }
         if(num>=n-1)
            break;
     }
 }
 int main()
 {
     double d;
     int kase=1;
     while(scanf("%d",&n)!=EOF)
     {
         if(n==0) break;
         for(i=0;i<n;i++)
            scanf("%lf%lf",&x[i],&y[i]);
            int mi=0;///记录边的数目

         for(i=0;i<n;i++)///任意两个顶点间的距离,有意思
            for(j=i+1;j<n;j++)
         {
             d=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
             edges[mi].u=i;
             edges[mi].v=j;
             edges[mi].w=d;
             mi++;
         }
         m=mi;
         qsort(edges,m,sizeof(edges[0]),cmp);///快速排序
         sumweight=0.0;
         Kruskal();
         if(kase>1)///第一组测试数据前有空格
            {
                printf("\n");
                 getchar();
            }
         printf("Case #%d:\n",kase);
         printf("The minimum distance is: %0.2f\n",sumweight);
         kase++;
     }
     return 0;
 }

测试数据:


例题二:网络(Network)

先输入顶点和边,然后是每条边的起始点和边的权值

输出描述:首先输出最长的单根网线的长度。然后输出设计方案:先输入一个整数p,代表所使用的网线的数目,然后输出p对顶点,表示每对网线所连接的集线器的编号

#include<cstdio>
#include<iostream>
#include<cstring>
#include<stdlib.h>
using namespace std;
#define MAXN 1005
#define MAXM 15005
struct edge
{
    int u,v,w;
 }edges[MAXM];
 int parent[MAXN];
 int ans[MAXN],ai;///存储的是依次选择的边的序号;数组ans的下标
 int n,m;
 int num,maxedge;///最长的边
 int i,j;
 void UFset()
 {
     for(i=0;i<n;i++)
        parent[i]=-1;
 }
 int find(int x)
 {
     int s=x;
     for(s=x;parent[s]>=0;s=parent[s]);
     while(s!=x)///压缩路径
     {
         int temp=parent[x];
         parent[x]=s;
         x=temp;
     }
     return s;
 }
 void Union(int R1,int R2)
 {
     int r1=find(R1);
     int r2=find(R2);
     int temp=parent[r1]+parent[r2];
     if(parent[r1]>parent[r2])///加权法则
     {
         parent[r1]=r2;
         parent[r2]=temp;
     }
     else
     {
         parent[r2]=r1;
         parent[r1]=temp;
     }
 }
 int cmp(const void *a,const void *b)
 {
     edge aa=*(const edge *)a;
     edge bb=*(const edge *)b;
     return aa.w-bb.w;
 }
 void Kruskal()
 {
     ai=0;
     num=0;
     maxedge=0;
     int u,v;
     UFset();
     for(i=0;i<m;i++)
     {
         u=edges[i].u;
         v=edges[i].v;
         if(find(u)!=find(v))
         {
             ans[ai]=i;
             ai++;
             if(edges[i].w>maxedge)
                maxedge=edges[i].w;
             num++;
             Union(u,v);
         }
         if(num>=n-1)
            break;
     }
 }
 int main()
 {
     int i,j;
     while(scanf("%d%d",&n,&m)!=EOF)
     {
         for(i=0;i<m;i++)
            scanf("%d%d%d",&edges[i].u,&edges[i].v,&edges[i].w);
         qsort(edges,m,sizeof(edges[0]),cmp);
         Kruskal();
         printf("%d\n",maxedge);
         printf("%d\n",num);
         for(i=0;i<num;i++)///ans[]存储的是依次选择的边的序号
            printf("%d %d\n",edges[ans[i]].u,edges[ans[i]].v);
     }
     return 0;
 }




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值