多边形入门 ——toj1813 A Round Peg in a Ground Hole

题目大意:

平面上有一个多边形的孔,给定一个圆形钉子的圆心坐标和半径,问能否放进去。如果孔是多边形则输出“HOLE IS ILL-FORMED“,否则输出能否放进去。

首先,我们需要判断一个多边形是不是凸多边形。我们只需要枚举各个边,看其他所有顶点是不是在它的同测。但是需要注意一个问题,有可能数据中有三点共线,开始我就是坐在这里挂了。代码如下:

bool isProtude(PT vpt[],int n)
{
    
int t,tt,pre;
    
for(t=0;t<n;t++)
    {
        tt
=0;
        
while(pre=sign(crossP(vpt[t],vpt[(t+1)%n],vpt[(t+2+tt)%n])),pre==0)
            tt
++;
        
for(;tt<n-2;tt++)
        {
            
double d=crossP(vpt[t],vpt[(t+1)%n],vpt[(t+2+tt)%n]);
            
if(sign(d)==0)
                
continue;
            
if(sign(d)!=pre)
                
return false;
        }
    }
    
return true;
}

接下来,我们就需要考虑一个多边形里头能不能放下一个指定的圆了。简单分析一下:

问题的实质是一个点到各个边的距离大于等于半径,而且点在多边形内

先看距离问题,我首先想到的是集训时讲到的判断点到线段的距离,只要点到所有边的距离都大于半径就可以了。那么这样写首先要判断点在线段所在直线的投影跟线段的关系,如果在线段上,则返回垂足到点的距离,否则返回两端点到点的距离的最小值。这需要判断点的投影跟线段的关系,需要求垂足,比较复杂。

在fifth的提示下,得到如下思路:

 

我们可以知道,只要圆的半径小于等于圆心到各边距离的最小值即可放入钉子。如果A点的投影在线段CB之外,比如F。那么|AF|>|AC|。但是很显然,|AE|>|AF|。那么我们需要用来比较的那个最小值并不会因此改变。所以,我们只需要在点到各边所在直线的距离中找出最小值,这个最小值必然等于我们最开始需要找的那个最小值。至此,问题大大化简。

接着,我么考虑边判断点是否早多边形内。

由于题目的特殊性,我们在此题中只需判断一个点是否在凸多边形内。如果注意到这点,就不必考虑复杂的凹多边形。那么,只要判断该点是否在所有边的同侧即可。代码如下:

 

bool inPoly(PT vpt[],int n,PT &pt)
{
    
int t;
    PT st,end;
    
int dr=sign(crossP(vpt[0],vpt[1],pt));
    
for(t=1;t<n;t++)
    {
        st
=vpt[t];
        end
=vpt[(t+1)%n];
        
if(sign(crossP(st,end,pt))!=dr)
            
return false;
    }
    
return true;
}

那么最后,判断是否适合的函数可以这么写:

 

bool isfit(PT vpt[],int n,double r,PT &pt)
{
    
if(!inPoly(vpt,pt))
        
return false;
    
int t,tt;
    PT st,end;
    
for(t=0;t<n;t++)
    {
        st
=vpt[t];
        end
=vpt[(t+1)%n];
        
double d=fabs(crossP(st,end,pt))/dis(st,end);
        
if(sign(R-d)==1)
            
return false;
    }
    
return true;


总结一下:

最大的收获是,对于一个几何题目,要充分发掘其几何性质,不要看到一个问题就想套用模板。多思考一下往往能够比模板带来更大的方便。另外,几何题目一定要考虑完全特殊情况,边界情况,才能做到万无一失。

 

posted @ 2008-09-06 22:35  DosXP  阅读(393)  评论(0编辑  收藏  举报