CF Round 172C. Rectangle Puzzle 几何(旋转,极角排序)

题意:给出矩形的长和宽,该矩形中心点在(0,0).
问将矩形逆时针旋转a度以后,和原先矩形的重叠面积?


先求出旋转后的四个顶点.可以得到4条直线.
求出这4条直线和原先矩形的交点.
这些交点构成组成的凸多边形显然就是重叠的部分.

将交点极角排序后,利用叉积求出面积可.注意斜率为0时特判一下.

#include <bits/stdc++.h>
using namespace std;
typedef long double ld; 
typedef pair<ld,ld> ii;
const int N=2e3+5;
const ld pi=acos(-1.0);
ld w,h,a,X,Y;
ld x[N],y[N];
ld getx(ld x,ld y)
{
	return x*cos(a)-y*sin(a);
}
ld gety(ld x,ld y)
{
	return x*sin(a)+y*cos(a);
}
void init()
{
	a*=pi/180.0;
	X=w/2.0,Y=h/2.0;
	x[1]=getx(-X,Y),y[1]=gety(-X,Y);
	x[2]=getx(-X,-Y),y[2]=gety(-X,-Y);
	x[3]=getx(X,-Y),y[3]=gety(X,-Y);
	x[4]=getx(X,Y),y[4]=gety(X,Y);
}
struct node{
	ld x,y;
	node(){}
	node(ld a,ld b){
		x=a,y=b;
	}
}p[N];
node operator-(const node&v1,const node&v2){
	return node(v2.x-v1.x,v2.y-v1.y);
}
ld product(node a,node b){
	return a.x*b.y-a.y*b.x; 
}
map<ii,int> mp;
int cnt=0;
bool check(ld x,ld y)
{
	if(mp[ii(x,y)])
		return false;
	return x>=-X&&x<=X&&y<=Y&&y>=-Y;
}
bool cmp(node a,node b)
{
	if(atan2(a.y,a.x)!=atan2(b.y,b.x))
		return atan2(a.y,a.x)<atan2(b.y,b.x);
	return a.x<b.x;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>w>>h>>a;
	if(a==0||a==180)
	{
		ld res=w*h;
		cout<<fixed<<setprecision(15)<<res<<'\n';
		return 0;
	}
	init();
	for(int i=1;i<=4;i++)
	{
		int j=(i==4?1:i+1);
		if(x[j]==x[i])	continue;
		ld k=(y[j]-y[i])/(x[j]-x[i]);
		//y-y[i]=k(x-x[i]).	
		for(int o1=0;o1<2;o1++)
		{
			for(int o2=0;o2<2;o2++)
			{
				ld rx=X,ry=Y;
				if(o1==0)	rx=-rx;
				if(o2==0)	ry=-ry;	
				ld nx=(ry-y[i]+k*x[i])/k,ny=k*(rx-x[i])+y[i];		
				if(check(nx,ry))
					p[++cnt]=node(nx,ry),mp[ii(nx,ry)]=true;
				if(check(rx,ny))
					p[++cnt]=node(rx,ny),mp[ii(rx,ny)]=true;
			}
		}
	}
	sort(p+1,p+1+cnt,cmp);
//	for(int i=1;i<=cnt;i++)
//		cout<<p[i].x<<' '<<p[i].y<<'\n'; 
	ld res=0; 
	for(int i=2;i<cnt;i++)
	{
		node p1=p[i]-p[1],p2=p[i+1]-p[1];
		res+=fabs(product(p1,p2));
	}
	res/=2.0;
	cout<<fixed<<setprecision(15)<<res<<'\n';
	return 0;
 } 

标程的解法: 只有两种情况:一种是平行四边形,一种利用对称性和相似来考虑.

#include<iostream>
#include<math.h>
#include<stdio.h>
using namespace std;
const double pi = acos(-1.0);
int main()
{
    double w,h,t;cin>>w>>h>>t;
    if(w<h)swap(w,h);
    if(t>=90)t=180-t;
    t=t*pi/180;
    double x1,y1,x2,y2;
    y2 = (h-tan(t)*w/(1+1.0/cos(t)))/(1+1/cos(t)-tan(t)*tan(t)/(1+1/cos(t)));
    x2 = tan(t)*y2;
    y1 = (w-y2*tan(t))/(1+1/cos(t));
    x1 = y1*tan(t);

    //cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;
    //cout<<tan(t)<<endl;
    if(tan(t/2)<h/w)
    {
        double ans = w*h - x1*y1 - x2*y2;
        printf("%.16f\n",ans);
    }
    else
    {
        double x = h / sin(t);
        printf("%.10f\n",w*h-(w-x)*h);
    }

}

极角排序是根据坐标系内每一个点与x轴所成的角,逆时针比较,。按照角度从小到大的方式排序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值