HDU 1162 Eddy's picture (Kruscal最小生成树)

本文介绍如何使用Kruskal算法解决绘画中的最短连线问题,通过计算点之间的距离,构造最小生成树,实现所有点的连接,同时确保总连线长度最短。文章详细展示了算法的实现过程,包括数据结构定义、关键函数如并查集的实现,以及快速排序等步骤。
摘要由CSDN通过智能技术生成

   文章作者:ktyanny 文章来源:ktyanny 转载请注明,谢谢合作。  

   

  Eddy 最近喜欢画画,他心太还说蛮好的,很自信自己会成文一名画家。……

  问题是:给你一些在画上的坐标点,每个点可以用墨水画直线。How many distants does your duty discover the shortest length which the ink draws? 

  ktyanny:显然是求最小生成树的问题。若要所有的点都相同,而且总的权值最小,当然是一棵最小生成树。刚好这两天在联系的Kruscal算法可以派上用场了。最近比较好奇优先队列,于是想到Kruscal算法:可以用并查集判断是否产生回路,那么,每次用选择权边最小的边可以用优先队列。刚好STL有个 priority_queue 优先队列,纠结了半晌,ac的是16MS, 使用以往的算法,先对边快排再帅选的办法,得到的结果是0MS。内在原因我暂时无法完全解释,不过可以说明的一点是,STL速度还是比较慢的。

  0MS  C++

/*
by ktyanny 
2009.12.12
*/
#include  < stdio.h >
#include 
< stdlib.h >
#include 
< string .h >
#include 
< math.h >

const   int  MAX  =   105 ;

typedef 
struct
{
    
double  a, b;
}point;

point v[MAX];

typedef 
struct
{
    
int  x, y;
    
double  w;
}edge;
const   int  MAXN  =   50005 ;
edge e[MAXN];
double  ans;

int  rank[MAXN];
int  pa[MAXN];

void  make_set( int  x)
{
    pa[x] 
=  x;
    rank[x] 
=   0 ;
}

int  find_set( int  x)
{
    
if (x  !=  pa[x])
        pa[x] 
=  find_set(pa[x]);
    
return  pa[x];
}

/* 按秩合并x,y所在的集合 */
void  union_set( int  x,  int  y,  double  w)
{
    x 
=  find_set(x);
    y 
=  find_set(y);
    
if (x  ==  y) return  ;
    ans 
+=  w;
    
if (rank[x]  >  rank[y]) /* 让rank比较高的作为父结点 */
    {
        pa[y] 
=  x;
    }
    
else  
    {
        pa[x] 
=  y;
        
if (rank[x]  ==  rank[y])
            rank[y]
++ ;
    }
}


int  cmp( const   void   * a,  const   void   * b)
{
    
return  ( ( * (edge  * )a).w  >  ( * (edge  * )b).w )  ?   1  :  - 1 ;
}

int  main()
{
    
int  n, i, j, x, y, k;
    
while (scanf( " %d " & n)  ==   1 )
    {
        
for (i  =   1 ; i  <=  n; i ++ )
            scanf(
" %lf%lf " & v[i].a,  & v[i].b);

        
/* 处理边的问题 */
        k 
=   0 ;
        
for (i  =   1 ; i  <=  n; i ++ )
        {
            
for (j  =  i; j  <=  n; j ++ )
            {
                e[k].x 
=  i;
                e[k].y 
=  j;
                e[k].w 
=  sqrt( double ( (v[i].a - v[j].a) * (v[i].a - v[j].a)  +
                    (v[i].b
- v[j].b) * (v[i].b - v[j].b) ) );
                k
++ ;
            }
        }

        
for (i  =   1 ; i  <=  n; i ++ )
            make_set(i);

        qsort(e, k, 
sizeof (e[ 0 ]), cmp);

        
/* Kruscal过程求最小生成树 */
        ans 
=   0.0 ;
        
for (i  =   0 ; i  <  k; i ++ )
        {
            x 
=  find_set(e[i].x);
            y 
=  find_set(e[i].y);
            
if (x  !=  y)
                union_set(x, y, e[i].w);
        }
        printf(
" %.2lf\n " , ans);
    }
    
return   0 ;
}

 

 

 

转载于:https://www.cnblogs.com/ktyanny/archive/2009/12/12/1622465.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值