圈水池
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
4
-
描述
-
有一个牧场,牧场上有很多个供水装置,现在牧场的主人想要用篱笆把这些供水装置圈起来,以防止不是自己的牲畜来喝水,各个水池都标有各自的坐标,现在要你写一个程序利用最短的篱笆将这些供水装置圈起来!(篱笆足够多,并且长度可变)
-
输入
-
第一行输入的是N,代表用N组测试数据(1<=N<=10)
第二行输入的是m,代表本组测试数据共有m个供水装置(3<=m<=100)
接下来m行代表的是各个供水装置的横纵坐标
输出
- 输出各个篱笆经过各个供水装置的坐标点,并且按照x轴坐标值从小到大输出,如果x轴坐标值相同,再安照y轴坐标值从小到大输出 样例输入
-
1 4 0 0 1 1 2 3 3 0
样例输出
-
0 0 2 3 3 0
-
第一行输入的是N,代表用N组测试数据(1<=N<=10)
分析:直接就是凸包问题,要注意的是如果多个点同时在一条直线上,并且这条直线式凸包的边时,所有的点都要输出!
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#define N 110
struct point{
int x,y;
double dis;
}p[N],res[N],temp;
int cmp2(const void *a, const void *b){
struct point *A,*B;
A=(struct point *)a;
B=(struct point *)b;
if(A->x!=B->x)
return A->x-B->x;
else
return A->y-B->y;
}
double getdis(struct point a, struct point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void find(int n){
int i,k=0;
temp=p[0];
for(i=1;i<n;i++){
if(p[i].y<temp.y||(p[i].y==temp.y&&p[i].x<temp.x)){
temp=p[i];
k=i;
}
}
if(k!=0){
temp=p[0];
p[0]=p[k];
p[k]=temp;
}
for(i=1,p[0].dis=0;i<n;i++){
p[i].dis=getdis(p[0],p[i]);
}
}
int check(struct point a, struct point b,struct point c){//叉乘
int x1,y1,x2,y2;
x1=b.x-a.x;
y1=b.y-a.y;
x2=c.x-b.x;
y2=c.y-b.y;
return x1*y2-x2*y1;
}
int cmp(const void *a, const void *b) {//极角排序
struct point *A,*B;
A=(struct point *)a;
B=(struct point *)b;
if((A->y-p[0].y)*(B->x-p[0].x)!=(A->x-p[0].x)*(B->y-p[0].y))
return atan2(A->y-p[0].y,A->x-p[0].x)>atan2(B->y-p[0].y,B->x-p[0].x)?1:-1;
else
return A->dis>B->dis?1:-1;
}
int graham(int n) {
int i,top;
res[0]=p[0];
res[1]=p[1];
for(i=2,top=2;i<n;i++){//逆时针扫描,如果发现向右偏则需要退栈,如果要等号则同一直线上的点只算端点
while(top>=1&&check(res[top-2],res[top-1],p[i])<=0)
top--;
res[top++]=p[i];
}
return top;
}
int main(){
int T,n,i,ans;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d %d",&p[i].x,&p[i].y);
}
find(n);//找到最下左位置的点,并将其放到p[0]位置
qsort(p+1,n-1,sizeof(p[0]),cmp);//按照极角排序,如果角度相同则按照与基点距离大小排序
ans=graham(n);
qsort(res,ans,sizeof(res[0]),cmp2);
for(i=0;i<ans;i++){//按照逆时针顺序输出凸包上的点
printf("%d %d\n",res[i].x,res[i].y);
}
}
system("pause");
return 0;
}
/*
11
2 0
4 0
0 1
1 1
3 1
2 2
5 2
1 3
4 3
2 4
4 4
0 1
1 3
2 0
2 4
4 0
4 4
5 2
*/