zoj 1369 || poj 1279 Art Gallery(半平面交第一题~~嘿嘿~)

211 篇文章 0 订阅
134 篇文章 1 订阅

经典题啊,求半平面交面积,也就是核的面积哈。

所谓的核呢就是在核里可以把多边形内部全部看到。凸多边形的话肯定是可以的啦。

所以只要把构成核这个多边形的点都找到,然后求面积即可。这个题没说输入是顺时针还是逆时针,可以用面积判断,我的多边形面积如果是顺时针的话求出来的是负的,改变下方向即可。


然后就是半平面交了。

解释下这个算法哈,其实用笔模拟一下就懂了。它是在一层一层缩小这个区域。

外层循环是用每一条边,筛选能看到它的点(或者说是内层形成的边吧),如果看不到(也就是内层有边得两点在他的两侧),那么就求这条边和当前内层循环边的交点作为核的点。交点是肯定能看到的啦。所以内层循环结束一次,点集就要变一次。

#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>

using namespace std;

const int MAX = 1510;
struct point{ double x,y;};
point p[MAX],s[MAX];
const double eps = 1e-6;
bool dy(double x,double y)	{	return x > y + eps;}	// x > y 
bool xy(double x,double y)	{	return x < y - eps;}	// x < y 
bool dyd(double x,double y)	{ 	return x > y - eps;}	// x >= y 
bool xyd(double x,double y)	{	return x < y + eps;} 	// x <= y 
bool dd(double x,double y) 	{	return fabs( x - y ) < eps;}  // x == y
double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 
{
	return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);
}
point l2l_inst_p(point u1,point u2,point v1,point v2)
{
	point ans = u1;
	double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/
				((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x));
	ans.x += (u2.x - u1.x)*t;
	ans.y += (u2.y - u1.y)*t;
	return ans;
}
void change_wise(point p[],int n)
{
	for(int i=0; i<n/2; i++)
		swap(p[i],p[n-i-1]);
}
void inst_hp(point p[],int n,point s[],int &len)
{
	point tp[MAX];	
	p[n] = p[0];
	for(int i=0; i<=n; i++)
		tp[i] = p[i];
	int cp = n,tc;
	for(int i=0; i<n; i++)
	{
		tc = 0;
		for(int k=0; k<cp; k++)
		{
			if( xyd(crossProduct(p[i],p[i+1],tp[k]),0.0) )// 顺时针的话是dyd 
				s[tc++] = tp[k];
			if( xy(crossProduct(p[i],p[i+1],tp[k])* 
					crossProduct(p[i],p[i+1],tp[k+1]),0.0) )
				s[tc++] = l2l_inst_p(p[i],p[i+1],tp[k],tp[k+1]);
		}
		s[tc] = s[0];
		for(int k=0; k<=tc; k++)
			tp[k] = s[k];
		cp = tc;
	}
	len = cp;
}
double area_polygon(point p[],int n)
{
	double s = 0.0;
	for(int i=0; i<n; i++)
		s += p[(i+1)%n].y * p[i].x - p[(i+1)%n].x * p[i].y;
	return s/2.0;
}
int main()
{
	int len,ncases,n;
	
	scanf("%d",&ncases);
	
	while( ncases-- )
	{
		scanf("%d",&n);
		for(int i=0; i<n; i++)
			scanf("%lf%lf",&p[i].x,&p[i].y);
		
		double area = area_polygon(p,n);
		if( xyd(area,0.0) ) change_wise(p,n);
		inst_hp(p,n,s,len);
		double ans = area_polygon(s,len);
		printf("%.2lf\n",fabs(ans));
	}

return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值