Graham-Scan小总结——toj2317 Wall

花了连天时间来弄toj 2317.Wall:http://acm.tju.edu.cn/toj/showp2317.html

这是一个赤裸裸的凸包,两天下来,收获不少,慢慢盘点一下。

关于题目本身的分析:

根据题意,用墙把城堡为起来,且周长最短,且墙于城堡至少间隔L。对于一个多边形(凸多边形,凹多边形),如果想要使把它所有点都包含在内的另外一个多边形周长最短,那么必定是该多边形的凸包。那么将凸包的各个边向外移动L的距离,各个边之间就会产生一定距离。如果用半径为L的圆弧连接各边,思考一下,得到这这个图形必然是边长在最短的符合条件的答案。所以,ans=凸包周长+2*PI*L。

 

对于整个题目而言,第一次作的时候在精度上吃亏了。其实根本就没有必要使用double,int完全足够了。因此在定义PT的时候直接定义为

struct PT

{

    int  x,y;

};

由于需要按照极角排序,同时还要处理极角相同的问题,那么cmp()应该这么写:

inline  int  crossP(PT a,PT b,PT c) //  abXac cross product
{
    
return  (c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y);
}
int  cmp(PT a,PT b)
{
    
int  re = crossP(pt[ 0 ],a,b);
    
if (re == 0 )
        
return  dis2(a,pt[ 0 ]) < dis2(b,pt[ 0 ]);
    
return  re > 0 ;
}

怎么理解sort()里头的cmp()?

我的理解是这样,sort完毕的序列中有a1在a2的前面,那么cmp(a1,a2)始终为true。也不知道准确不准确,请大虾指点~


解决了以上一个小问题,那么这下,我们的Graham-Scan就好写了。

// Graham-Scan
// int graham(PT pt[],PT stk[],int n);
// pt[]是所有点;stk[]返回凸包上的点,逆时针;n是所有点的总数;
// 返回凸包上点的个数。

int  graham(PT pt[],PT stk[], int  n)
{
    
int  t,tt = 0 ;
    
for (t = 1 ;t < n;t ++ )
    {
        
if (pt[t].y < pt[tt].y  ||  (pt[t].y == pt[tt].y  &&  pt[t].x < pt[tt].x))
            tt
= t;
    }
// find the lowest & leftest point
    swap(pt[ 0 ],pt[tt]);
    sort(pt
+ 1 ,pt + n,cmp);
     for (t = 0 ;t <= 2 ;t ++ )
        stk[t]
= pt[t];
    
int  ps = 2 ;
    
for (t = 3 ;t < n;t ++ )
    {
        
while (crossP(stk[ps - 1 ],stk[ps],pt[t]) <= 0 )
            ps
-- ;
        stk[
++ ps] = pt[t];
    }
    
return  ps + 1 ;
}

 

That's all.

你可能感兴趣的:(总结)