ZOJ 2419-- Triangle-凸包+旋转卡壳求最大面积三角形(计算几何)
2016-05-15 17:46
591 查看
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=40259
题意 给n个点,求出面积最大的三角形面积
显然 三点落在凸包上。nlogn找凸包。
然后 可以证明凸包上的点不超过 sqrt(m),m为坐标系范围,m=1e4
所以可以用sqrt(m)*sqrt(m)的方法枚举两个点,然后旋转卡壳 osqrt(m) 遍历三角形得到答案
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const double pi=acos(-1.0);
double eps=1e-8;
struct POINT
{
double x;
double y;
POINT(double a=0, double b=0)
{
x=a; //constructor
y=b;
}
};
struct LINESEG
{
POINT s;
POINT e;
LINESEG(POINT a, POINT b)
{
s=a;
e=b;
}
LINESEG() { }
};
struct LINE // 直线的解析方程 a*x+b*y+c=0 为统一表示,约定 a >= 0
{
double a;
double b;
double c;
LINE(double d1=1, double d2=-1, double d3=0)
{
a=d1;
b=d2;
c=d3;
}
};
double multiply(POINT sp,POINT ep,POINT op)
{
return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}
double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离
{
return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) );
}
POINT p[50005];
POINT ans[50005];
bool cmp(const POINT& a,const POINT& b)//P[0]指PointSet
{
if ( multiply(a,b,p[0])>0 || // 极角更小
(multiply(a,b,p[0])==0) && //极角相等,距离更短
dist(p[0],a)<dist(p[0],b)
)
return true;
else
return false;
}
void Graham_scan(POINT PointSet[],POINT ch[],int n,int &len) //求凸包顶点集
{
int i,j,k=0,top=1;
POINT tmp;
// 选取PointSet中y坐标最小的点PointSet[k],如果这样的点有多个,则取最左边的一个
for(i=1; i<n; i++)
if ( PointSet[i].y<PointSet[k].y || (PointSet[i].y==PointSet[k].y) && (PointSet[i].x<PointSet[k].x) )
k=i;
tmp=PointSet[0];
PointSet[0]=PointSet[k];
PointSet[k]=tmp; // 现在PointSet中y坐标最小的点在PointSet[0]
sort(PointSet+1,PointSet+n,cmp);
ch[0]=PointSet[0];
ch[1]=PointSet[1];
for (i=2; i<n; i++)
{
while (top>0 &&multiply(PointSet[i],ch[top],ch[top-1])>=0)
top--;
ch[++top]=PointSet[i];
}
len=top+1;
}
double ptoldist(POINT p,LINESEG l)
{
return abs(multiply(p,l.e,l.s))/dist(l.s,l.e);
}
double rotating_calipers(POINT *ch,int n)
{
ch
=ch[0];
double ans=-1;
for (int i=0; i<n; i++)
{
int q=(i+2)%n;
for(int p=(i+1)%n; (p+1)%n!=i ; p=(p+1)%n)
{
double tmp=-1;
while (1)
{
double tmp2=ptoldist(ch[q],LINESEG(ch[p],ch[i]));
if (tmp2>tmp)
{
tmp=tmp2;
q++;
if (q==n)
q=0;
}
else
{ q--;if (!q) q=n-1; break;}
}
ans=max(ans,tmp*dist(ch[p],ch[i])/2);
}
}
return ans;
}
int main()
{
int i,j;
int n;
while (scanf("%d",&n)!=EOF && n!=-1)
{
for (i=0; i<n; i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
}
int len=-1;
Graham_scan(p,ans,n,len);
printf("%.2lf\n",rotating_calipers(ans,len));
}
return 0;
}
题意 给n个点,求出面积最大的三角形面积
显然 三点落在凸包上。nlogn找凸包。
然后 可以证明凸包上的点不超过 sqrt(m),m为坐标系范围,m=1e4
所以可以用sqrt(m)*sqrt(m)的方法枚举两个点,然后旋转卡壳 osqrt(m) 遍历三角形得到答案
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const double pi=acos(-1.0);
double eps=1e-8;
struct POINT
{
double x;
double y;
POINT(double a=0, double b=0)
{
x=a; //constructor
y=b;
}
};
struct LINESEG
{
POINT s;
POINT e;
LINESEG(POINT a, POINT b)
{
s=a;
e=b;
}
LINESEG() { }
};
struct LINE // 直线的解析方程 a*x+b*y+c=0 为统一表示,约定 a >= 0
{
double a;
double b;
double c;
LINE(double d1=1, double d2=-1, double d3=0)
{
a=d1;
b=d2;
c=d3;
}
};
double multiply(POINT sp,POINT ep,POINT op)
{
return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}
double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离
{
return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) );
}
POINT p[50005];
POINT ans[50005];
bool cmp(const POINT& a,const POINT& b)//P[0]指PointSet
{
if ( multiply(a,b,p[0])>0 || // 极角更小
(multiply(a,b,p[0])==0) && //极角相等,距离更短
dist(p[0],a)<dist(p[0],b)
)
return true;
else
return false;
}
void Graham_scan(POINT PointSet[],POINT ch[],int n,int &len) //求凸包顶点集
{
int i,j,k=0,top=1;
POINT tmp;
// 选取PointSet中y坐标最小的点PointSet[k],如果这样的点有多个,则取最左边的一个
for(i=1; i<n; i++)
if ( PointSet[i].y<PointSet[k].y || (PointSet[i].y==PointSet[k].y) && (PointSet[i].x<PointSet[k].x) )
k=i;
tmp=PointSet[0];
PointSet[0]=PointSet[k];
PointSet[k]=tmp; // 现在PointSet中y坐标最小的点在PointSet[0]
sort(PointSet+1,PointSet+n,cmp);
ch[0]=PointSet[0];
ch[1]=PointSet[1];
for (i=2; i<n; i++)
{
while (top>0 &&multiply(PointSet[i],ch[top],ch[top-1])>=0)
top--;
ch[++top]=PointSet[i];
}
len=top+1;
}
double ptoldist(POINT p,LINESEG l)
{
return abs(multiply(p,l.e,l.s))/dist(l.s,l.e);
}
double rotating_calipers(POINT *ch,int n)
{
ch
=ch[0];
double ans=-1;
for (int i=0; i<n; i++)
{
int q=(i+2)%n;
for(int p=(i+1)%n; (p+1)%n!=i ; p=(p+1)%n)
{
double tmp=-1;
while (1)
{
double tmp2=ptoldist(ch[q],LINESEG(ch[p],ch[i]));
if (tmp2>tmp)
{
tmp=tmp2;
q++;
if (q==n)
q=0;
}
else
{ q--;if (!q) q=n-1; break;}
}
ans=max(ans,tmp*dist(ch[p],ch[i])/2);
}
}
return ans;
}
int main()
{
int i,j;
int n;
while (scanf("%d",&n)!=EOF && n!=-1)
{
for (i=0; i<n; i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
}
int len=-1;
Graham_scan(p,ans,n,len);
printf("%.2lf\n",rotating_calipers(ans,len));
}
return 0;
}
相关文章推荐
- MySQL学习笔记--触发器的创建与删除及使用注意事项
- NAT分类和利弊
- java29接口的应用
- 状态模式
- (四)JAVA使用POI操作excel
- 前方有坑!独立移动开发者绕坑指南(安卓篇)
- 国防科大校赛决赛-final(镜像赛) Problem C: XueXX and Chessboard
- LinuxC编程一站式学习(C语言本质)
- 单例模式
- 今天是下午有雨
- 【mybatis基础】高级映射:一对一查询
- Android FlexboxLayout基本用法
- 【Asp.Net】——网页设计中的url,src,href的区别
- 算法模型好坏、评价标准、算法系统设计
- ecshop邮件服务器设置注意事项
- 如何设置幻灯片自动播放
- SVN简单介绍
- 有疑问
- CentOS6.5+Nginx1.9+Mysql5.7+PHP7.0.6(LNMP)环境配置
- C/C++对文件的读写