算法专题
poj 2007 Scrambled Polygon
题目
给你 n n n个点,让你对于原点进行极角排序
分析
那么这个极角排序究竟有什么用呢,反正对于作者的理解,就是对于某个点按照顺时针的顺序排序,那么一般来说会取 y y y坐标最小的情况下,且 x x x坐标最小(反正我打凸包就是这么打的),然后对于这个点极角排序,但是这道题貌似有点水分,于是就把它放在第一题,那问题是如何极角排序呢,就是求出按照叉积的大小排序,那么叉积是干什么的呢,就是计算三个点组成的平行四边形的面积,通过叉积可以判断两个点对于另一个点是位于顺时针方向还是逆时针方向,这样就可以确认答案
代码
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
#define p(x) ((x)*(x))
#define cj(i,j,k) ((i.x-k.x)*(j.y-k.y)-(j.x-k.x)*(i.y-k.y))
#define dis(i,j) sqrt(p(i.x-j.x)+p(i.y-j.y))
using namespace std;
struct site{int x,y;}a[51];
int len;
bool cmp(site i,site j){
rr double t=cj(i,j,a[1]);
return t>0||(!t&&dis(i,a[1])<dis(j,a[1]));
}
signed main(){
rr int x,y;
while (scanf("%d%d",&x,&y)==2) a[++len]=(site){x,y};
sort(a+2,a+1+len,cmp);
for (rr int i=1;i<=len;++i) printf("(%d,%d)\n",a[i].x,a[i].y);
return 0;
}
洛谷 2742 圈奶牛
题目
给定 n n n个点,求它们的凸包的周长
分析
首先先说一下凸包,凸包的定义如图所示
那么如何实现找到凸包呢,那么我们首先要确定一个基准点,最好是
y
y
y坐标最小且
x
x
x坐标最小的点,然后对于其它点做一次极角排序,为的就是使它们方向相同,那如果三个点的叉积为非负数,那么说明后一个点在前一个点的逆时针方向,那么肯定不会更优,所以就把后一个点删去,这样用栈的方式求得凸包的每一个点,时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
代码
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
#define p(x) ((x)*(x))
#define cj(i,j,k) ((i.x-k.x)*(j.y-k.y)-(j.x-k.x)*(i.y-k.y))
#define dis(i,j) sqrt(p(i.x-j.x)+p(i.y-j.y))
using namespace std;
struct site{double x,y;}a[10001];
int n,k,zh[10001],len; double ans;
bool cmp(site i,site j){
rr double t=cj(i,j,a[1]);
return t>0||(!t&&dis(i,a[1])<dis(j,a[1]));
}
signed main(){
scanf("%d",&n); k=1;
for (rr int i=1;i<=n;++i){
scanf("%lf%lf",&a[i].x,&a[i].y);
if (a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x)) k=i;
}
swap(a[1],a[k]); sort(a+2,a+1+n,cmp);
zh[1]=1; zh[2]=2; zh[3]=3; len=3;
for (rr int i=4;i<=n;++i){
while (cj(a[i],a[zh[len]],a[zh[len-1]])>=0) --len;
zh[++len]=i;
}
for (rr int i=1;i<len;++i) ans+=dis(a[zh[i]],a[zh[i+1]]);
return !printf("%.2lf",ans+dis(a[zh[1]],a[zh[len]]));
}
zoj 1453 hdu 1392 Surround the Trees
分析
题目同上,主要是 n = 1 n=1 n=1时输出0, n = 2 n=2 n=2时输出 d i s dis dis
代码(hdu,zoj的n=2时要加倍)
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
#define p(x) ((x)*(x))
#define cj(i,j,k) ((i.x-k.x)*(j.y-k.y)-(j.x-k.x)*(i.y-k.y))
#define dis(i,j) sqrt(p(i.x-j.x)+p(i.y-j.y))
using namespace std;
struct site{double x,y;}a[101];
int n,zh[101],len;
bool cmp(site i,site j){
rr double t=cj(i,j,a[1]);
return t>0||(!t&&dis(i,a[1])<dis(j,a[1]));
}
signed main(){
while (scanf("%d",&n)==1&&n){
rr int k=1; rr double ans=0;
for (rr int i=1;i<=n;++i){
scanf("%lf%lf",&a[i].x,&a[i].y);
if (a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x)) k=i;
}
if (n==1) {printf("0.00\n"); continue;}
if (n==2) {printf("%.2lf\n",dis(a[1],a[2])); continue;}
swap(a[1],a[k]); sort(a+2,a+1+n,cmp);
zh[1]=1; zh[2]=2; zh[3]=3; len=3;
for (rr int i=4;i<=n;++i){
while (cj(a[i],a[zh[len]],a[zh[len-1]])>=0) --len;
zh[++len]=i;
}
for (rr int i=1;i<len;++i) ans+=dis(a[zh[i]],a[zh[i+1]]);
printf("%.2lf\n",ans+dis(a[zh[1]],a[zh[len]]));
}
return 0;
}
poj 3348 Cows
题目
计算凸包的面积
分析
那么就是求完凸包的每一个点后计算多边形的面积
代码
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
#define p(x) ((x)*(x))
#define cj(i,j,k) ((i.x-k.x)*(j.y-k.y)-(j.x-k.x)*(i.y-k.y))
#define dis(i,j) sqrt(p(i.x-j.x)+p(i.y-j.y))
using namespace std;
struct site{int x,y;}a[10001];
int n,zh[10001],len,k=1; double ans;
bool cmp(site i,site j){
rr double t=cj(i,j,a[1]);
return t>0||(!t&&dis(i,a[1])<dis(j,a[1]));
}
signed main(){
scanf("%d",&n);
for (rr int i=1;i<=n;++i){
scanf("%d%d",&a[i].x,&a[i].y);
if (a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x)) k=i;
}
swap(a[1],a[k]); sort(a+2,a+1+n,cmp);
zh[1]=1; zh[2]=2; zh[3]=3; len=3;
for (rr int i=4;i<=n;++i){
while (cj(a[i],a[zh[len]],a[zh[len-1]])>=0) --len;
zh[++len]=i;
}
for (rr int i=2;i<=len;++i) ans+=cj(a[zh[i]],a[zh[i-1]],a[1]);
if (ans<0) ans=-ans;
printf("%d",(int)(ans/2/50));
return 0;
}
后续
计算几何属于那种想到怎么做又做不出来的题目,所以应该大量刷题了