题意:一个由钉子加绳子围成的凸多边形农场。现 在绳子和部分钉子缺失,问能否通过剩余的钉子确定原农场的样子。
思路:做凸包。当围成的凸包每条边上都有至少3个钉子(含端点),则可确定原农场样子。因为如果只有两个钉子,那么可能存在一个消失的钉子位于这条边的外面,使得所围的农场变大,且凸包性质没变。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 1005
int T,n,top;
struct point {
int x,y;
}p[N];
int stack[N];
int multi(point a,point b,point c){
return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
}
int dist(point a,point b){
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}
int cmp(point a,point b){
int j = multi(p[0],a,b);
if(j == 0)
return dist(p[0],a) < dist(p[0],b);
return j>0;
}
int test(){
int i,j;
if(top == 1)//最后凸包成为一条直线
return 0;
for(j = 0;j<top;j++){
if(stack[j] == stack[j+1]-1)
return 0;//表示凸包中两点之间没有点,那么这条直线未必是原来农场中存在的
for(i = stack[j]+1;i<=stack[j+1]-1 && multi(p[0], p[i], p[stack[top]])!=0;i++)
if(multi(p[stack[j]], p[stack[j+1]], p[i]) != 0)//有在凸包之内的点的情况
return 0;
}
if(i==n-1)//原点到逆时针最后一个点之间没有点的情况
return 0;
for(;i<n-1;i++)
if(multi(p[0], p[i], p[stack[top]]) != 0)
return 0;
return 1;
}
int main(){
scanf("%d",&T);
while(T--){
int i,j,start = 1;
top = -1;
scanf("%d",&n);
for(i = 1;i<=n;i++){
scanf("%d %d",&p[i].x,&p[i].y);
if(p[i].y<p[start].y || (p[i].y==p[start].y && p[i].x<p[start].x))
start = i;
}
if(n==1){
printf("NO\n");
continue;
}
p[0] = p[start];
for(i = start+1;i<=n;i++)
p[i-1] = p[i];
sort(p,p+n,cmp);
stack[++top] = 0;
stack[++top] = 1;
for(i = 2;i<n;i++){
while(top && multi(p[stack[top-1]],p[stack[top]],p[i])<=0)
top--;
stack[++top] = i;
}
if(test())
printf("YES\n");
else
printf("NO\n");
}
}
本文介绍了一种算法,该算法通过剩余的钉子来判断是否可以确定原凸多边形农场的完整形状。核心思路是利用凸包算法,并确保每条边上至少有三个钉子,以此来排除不确定因素。

被折叠的 条评论
为什么被折叠?



