您的位置:首页 > 产品设计 > UI/UE

计算几何-UESTC 484 Division

2015-05-27 12:54 260 查看
题意:给一个萌点,找到经过这个萌点的射线可以平分多边形。

题解:

1、遍历角度会wa,需要遍历距离。因为枚举角度的话会用到三角函数,听说会损失精度。

2、二分的时候二分五六十次不然100次就差不多了,我把精度弄成了l和r相差10的-7次方就wa了。真2。

3、如何判断两个端点是不是在边上呢?!我一开始枚举斜率,这么损失精度的方法真是蠢死了。叉积:a X b = |a||b|sinα 。也就是说a和b的角度小于180的话,叉积大于0,大于180的话,叉积小于0。最右的端点和萌点的连线和其余点和萌点的连线叉乘一定全都大于0或者共线,最左端点和萌点的连线和萌点的连线叉乘一定全部大于0或者共线。

4、注意多边形的顶点。判断是否在线段上的时候算左边点不算右边点就好了。而且还要判一下交点是不是多边形顶点。

5、总结一下。先通过叉乘不小于0找到最右端点,再通过叉乘不大于0找到最左端点,做一条线段,遍历距离。然后得到一条直线和一个多边形。

6、5之后的方法1:通过叉乘找到所有在这条线右边的顶点,加入新多边形的点集,(算上共线),找到和线段的交点加入点集(不算上端点)。

7、5之后的方法2:记录端点号,把两个交点加入点集,以及从较小端点到较大端点的所有端点序号。(注意判一下是不是交点,如果已经加进去过了就别加了)。然后看看最右端点在不在集合中。以此来判断算出的多边形面积是啥

8、6或者7之后,得到新多边形面积,如果刚好是“多边形/2”就找到了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define SIZE_N 330
#define INF 0x3f3f3f3f
using namespace std;
const double PI = acos(-1);
const double eps = 1e-8;
const double eps1 = 1e-5;
int cmp(double x)
{
if (fabs(x)< eps) return 0;
if (x>0) return 1;
return -1;
}
struct point
{
double x,y;
point(){}
point (double a, double b): x(a),y(b) {}
friend point operator + (const point &a, const point &b){
return point(a.x + b.x, a.y + b.y);
}
friend point operator - (const point &a,const point &b){
return point(a.x - b.x, a.y - b.y);
}
friend point operator * (const double &a, const point &b){
return point(a * b.x, a * b.y);
}
friend point operator * (const point &a, const double &b){
return point(a.x * b, a.y * b);
}
friend point operator / (const point &a, const double &b){
return point(a.x/b, a.y/b);
}
friend bool operator == (const point &a, const point &b){
return cmp(a.x-b.x) == 0 && cmp(a.y-b.y) == 0;
}
}p[SIZE_N],ptemp[SIZE_N];
struct line
{
point a,b;
}line1[SIZE_N];
double l,r;//从0到1二分距离
int N;
int left,right;//最左边点的序号和最右边点的序号

double ar;
double det(const point &a,const point &b)
{
return a.x * b.y -a.y * b.x;
}

double dot(const point &a,const point &b)
{

return a.x * b.x + a.y *b.y;
}

bool PointOnSegment (point p,point s,point t)
{//p在st上面!
return cmp(det(p-s,t-s))== 0 && cmp(dot(p-s,p-t))<= 0;
}

bool parallel(line a, line b)
{
return !cmp(det(a.a - a.b, b.a - b.b));
}

bool line_make_point(line a,line b, point &res)
{
if (parallel(a,b)) return 0;
double s1 = det(a.a-b.a, b.b - b.a);
double s2 = det(a.b - b.a, b.b - b.a);
res = (s1 * a.b - s2 * a.a)/(s1-s2);
if(b.b == res )
return 0;
if (PointOnSegment(res,b.a,b.b))
return 1;
return 0;
}
int cmin,cmax;
point res1,res2;

double area(point a[],int n)
{
double sum = 0;
a
= a[0];
for (int i = 0; i < n; i++){
sum+= det(a[i],a[i+1]);
}
sum = fabs(sum);
return sum/2.0;
}

double getarea(int cmin,int cmax)
{
int num = 0;
ptemp[num++] = res1;
int isright = 0;
for (int i = cmin; i < cmax; i++){
ptemp[num++] = p[i];
if (i == right)
isright = 1;
}
if (!(res2 == p[cmax-1]) ){
ptemp[num++] = res2;
}
if (isright == 1)
return area(ptemp,num);
else
return ar - area(ptemp,num);
}

bool check(point P, point now)
{
line li;
li.a = P;
li.b = now;
int sum = 0;
point res;
int cmin = -1,cmax;
for (int i = 1; i <= N; i++){
if (line_make_point(li,line1[i],res)){
sum++;
if (sum == 1){
res1 = res;
cmin = i;
}
else{
res2 = res;
cmax = i;
}
}
}
if ( cmp(getarea(cmin,cmax )-(ar/2.0) )==-1)
return 1;
return 0;
}

double getdis(point p,point q)
{
return sqrt((p.y-q.y)*(p.y-q.y) + (p.x-q.x)*(p.x-q.x));
}

double trans(double x)
{
if(abs(x) < eps1) return abs(x);
else return x;
}

void getlr(point P)
{
for (int i = 0; i < N; i++){
int isr = 0,isl = 0;
for (int j = 0; j < N; j++){
if (j != i){
if (!(cmp(det(p[i]-P,p[j]-P) ) != -1))
isr = 1;
else
isl = 1;
}
}
if (isr != 1){
right = i;
}
if (isl != 1)left = i;
}
}

int main()
{
//freopen("input.txt","r",stdin);
int T;
scanf("%d",&T);
int cas = 1;
while (T--){
scanf("%d",&N);
for (int i = 0; i < N; i++){
scanf("%lf %lf",&p[i].x,&p[i].y);
if (i != 0){
line1[i].a = p[i-1];
line1[i].b = p[i];
}
}ar = area(p,N);
line1
.a = p[N-1];
line1
.b = p[0];//从第1条线一直到第N条线
point P;
scanf("%lf %lf",&P.x,&P.y);

point pr,pl;
getlr(P);
pr = p[right];
pl = p[left];
r = 1.0;
l = 0;
double res0;
point resc;
point now;
int a7 = 60;
while (a7--){
double mid = (r + l)/(2.0);
now = pl + mid * (pr-pl);
if (check(P,now)){
resc = now;
r = mid;
}else
l = mid;
}
double dis = getdis(now,P);
printf("Case #%d: %.4f %.4f\n",cas++,trans((now.x-P.x)/dis+eps),trans((now.y-P.y)/dis+eps));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  计算几何