圈水池
时间限制:
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
来源
- [张洁烽]原创 上传者
介绍一下用到的凸包思想
什么是凸包?
假设平面上有p0~p12共13个点,过某些点作一个多边形,使这个多边形能把所有点都“包”起来。当这个多边形是凸多边形的时候,我们就叫它“凸包”。
首先,找一个凸包上的点,把这个点放到第一个点的位置P0。然后把P1~Pm 按照P0Pi的方向排序,可以用矢量积(叉积)判定。
做好了预处理后开始对堆栈中的点<p3,p4,...,pm>中的每一个点进行迭代,在第7到8行的while循环把发现不是凸包中的顶点的点从堆栈中移去。(原理:沿逆时针方向通过凸包时,在每个顶点处应该向左转。因此,while循环每次发现在一个顶点处没有向左转时,就把该顶点从堆栈中弹出。)当算法向点pi推进、在已经弹出所有非左转的顶点后,就把pi压入堆栈中。
举例如下:
#include<iostream> #include<algorithm> using namespace std; struct point { double x,y; }p[300],s[300];//点 int cmp(point a,point b) { if(a.x==b.x) return a.y<b.y; else return a.x<b.x; } bool judge(point a, point b, point c)//ab×ac叉乘 { int abx = b.x-a.x; int aby = b.y-a.y; int acx = c.x-a.x; int acy = c.y-a.y; if(abx*acy - aby*acx > 0) return true; return false; } int main() { int n; cin>>n; while(n--) { int m; cin>>m; for(int i=0;i<m;i++) cin>>p[i].x>>p[i].y; // cout<<endl; sort(p,p+m,cmp); //for(int j=0;j<m;j++) // cout<<p[j].x<<" "<<p[j].y<<endl; // cout<<endl; int top=0; for(int i=0;i<m;i++) { while(top>=2&&!judge(s[top-2],s[top-1],p[i])) top--; s[top++]=p[i]; } // for(int j=0;j<top;j++) // cout<<s[j].x<<" "<<s[j].y<<endl; // cout<<endl; int t=top-1; for(int i=m-1;i>=0;i--) { while(top>=t+2&&!judge(s[top-2],s[top-1],p[i])) top--; s[top++]=p[i]; } --top;//上凸包和下凸包首尾重复 sort(s,s+top,cmp); for(int j=0;j<top;j++) cout<<s[j].x<<" "<<s[j].y<<endl; } return 0; }
参考链接 点击打开链接 -
第一行输入的是N,代表用N组测试数据(1<=N<=10)