zoj 1369

裸的半平面交。

這個題沒說輸入是順時針還是逆時針,可以用面積判斷,多邊形面積如果是順時針,面積爲負,改變下方向即可。

 

粘兩個模板。

code 1:

//書27頁 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
#define MAXN 1510
const double EPS=1e-12;
//半平面爲向量表示,平面維宇向量左側
struct point{
       double x,y; } convex[MAXN];
struct line{
       point a,b;
       double ang; //角度(弧度) 
       }l[MAXN],st[MAXN];
int n,ccnt;
 double  operator *(const point &x,const point &y)//向量叉乘3
 { return x.x*y.y-x.y*y.x; }
 point operator -(point x,const point &y) //向量減法
 { x.x-=y.x,x.y-=y.y; 
   return x; }
 point operator *(const line &x,const line &y)//直線求交點 
 { double a1=(y.b-x.a)*(y.a-x.a),a2=(y.a-x.b)*(y.b-x.b);
   point r;
   r.x=(x.a.x*a2+x.b.x*a1)/(a2+a1);
   r.y=(x.a.y*a2+x.b.y*a1)/(a2+a1);
   return r;
 }
 bool  operator ==(const point &a,const point &b)//判斷共點 
 { return fabs(a.x-b.x)<EPS&&fabs(a.y-b.y)<EPS; }
 bool operator <(const line &x,const line &y)//爲極角排序重載的運算符
{
  if(fabs(x.ang-y.ang)<EPS)  return (y.b-x.a)*(x.b-y.a)>EPS;
  return x.ang<y.ang;
}
bool judgeout(const line &x,const point &p)//判斷點和平面的關係
{return (p-x.a)*(x.b-x.a)>EPS; }
bool parellel(const line &x,const line &y)//判斷兩個向量是否平行
{ return fabs((x.b-x.a)*(y.b-y.a))<-EPS; }


void inputdata()
{
  scanf("%d",&n);
  scanf("%lf%lf",&l[0].b.x,&l[0].b.y); 
  l[n-1].a.x=l[0].b.x,l[n-1].a.y=l[0].b.y;
  for(int i=1;i<n;i++)
  {
    scanf("%lf%lf",&l[i].b.x,&l[i].b.y);
    l[i-1].a.x=l[i].b.x,l[i-1].a.y=l[i].b.y;
  }
  for(int i=0;i<n;i++)
    l[i].ang=atan2(l[i].b.y-l[i].a.y,l[i].b.x-l[i].a.x);
}

double hplaneintersection()
{
  int top=1,bot=0;
  sort(l,l+n); //極角排序 
  int tmp=1;
   for(int i=1;i<n;++i)
    if(l[i].ang-l[i-1].ang>EPS) l[tmp++]=l[i];//去重 
    n=tmp;
    st[0]=l[0],st[1]=l[1];
    for(int i=2;i<n;++i)
    {
       if(parellel(st[top],st[top-1])||parellel(st[bot],st[bot+1]))  return 0;
       while(bot<top&&judgeout(l[i],st[top]*st[top-1])) top--;
       while(bot<top&&judgeout(l[i],st[bot]*st[bot+1])) bot++;
     st[++top]=l[i];
    }
    while((bot<top&&judgeout(st[bot],st[top]*st[top-1]))) top--;
    while((bot<top&&judgeout(st[top],st[bot]*st[bot+1])))bot++;
     if(top<bot+1) return 0.00;
     st[++top]=st[bot];
    ccnt=0;
    for(int i=bot;i<top;i++)
    convex[ccnt++]=st[i]*st[i+1];
    double ans=0;
    convex[ccnt]=convex[0];
    for(int i=0;i<ccnt;i++)
    ans+=convex[i]*convex[i+1];
    return ans/2;
}

double chackdirection()
{
 double ans=0;
 for(int i=0;i<n;++i)
 ans+=l[i].a*l[i].b;
 return ans;
}

void changedirection()
{
  for(int i=0;i<n;++i)
  swap(l[i].a,l[i].b);
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
      inputdata();
      if(chackdirection()<0)  changedirection();
      printf("%.2f\n",hplaneintersection());
    }
 return 0;
}
 


code 2:

 

/*
半平面交。

解釋下這個算法哈,其實用筆模擬一下就懂了。它是在一層一層縮小這個區域。

外層循環是用每一條邊,篩選能看到它的點(或者說是內層形成的邊吧),

如果看不到(也就是內層有邊得兩點在他的兩側),那麼就求這條邊和當前內層循環邊的交點作爲核的點。

交點是肯定能看到的啦。所以內層循環結束一次,點集就要變一次。
*/
#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;


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章