HDU3882

本文介绍了一种在三维空间中模拟特定点光源对平面上点进行光照的效果,并判断哪些点处于阴影中的算法。通过计算点光源到各顶点射线与参考平面的交点个数来确定未被照射区域的面积是否有限且非零,同时计算给定点集内未被照射点的比例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

哈我好像是HDU上惟一一个过了这题的人(可惜是用vjudge交的不是我自己的账号)……

题意很简单,就是说给定空间中很多点和一个参照点,对于空间中的其他点来说,如果这个点在这个参照点到给定的其中三个点的射线所组成的的无穷三棱锥里,那么这点就是没有被照射到,否则就是照射到了。现在给定一个参考平面,不过参照点,问这个平面上没有被照射到的点所组成区域的面积是否有限且不为零;如果是,再输出另给定的一些点中没有被照射到的点占的百分比。

这题表面上看很复杂,但是注意到,因为参考平面不过参照点,事实上不被照射的面积只与参照点到所有给定点的射线与该平面的交点个数t有关。如果t=n,则一定有限,如果t=0,则一定为零,其他情况就是无穷。而对于有限的情况,同样要考虑一个新给定点有没有被照射到,只要考虑参照点到它的射线是否与参考平面相交,以及交点是否在已给定点在这个平面上组成的凸包内部(不包括边界,这点可以直接从样例看出)。当然注意考虑参照点与给顶点重合的情况。虽然参考平面可能倾斜,但总可以把其上的点投影到三个坐标面,这样就可以用二维的凸包。具体看程序吧……

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;

const double eps=1e-9;
int dcmp(double x){if(x<-eps) return -1;return x>eps;}
struct point3
{
	double x,y,z;
	point3(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
	void read(){int xt,yt,zt;scanf("%d %d %d",&xt,&yt,&zt);x=xt;y=yt;z=zt;}
};

point3 operator -(point3 a,point3 b){return point3(a.x-b.x,a.y-b.y,a.z-b.z);}
point3 operator *(point3 a,double b){return point3(a.x*b,a.y*b,a.z*b);}
bool operator <(point3 a,point3 b){return a.x<b.x||(dcmp(a.x-b.x)==0&&a.y<b.y)||(dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0&&a.z<b.z);}
bool operator ==(point3 a,point3 b){return !(a<b||b<a);}
double dot(point3 a,point3 b){return a.x*b.x+a.y*b.y+a.z*b.z;}
double cross(point3 a,point3 b){return a.x*b.y-a.y*b.x;}
double length(point3 a){return sqrt(dot(a,a));}

int convexhull(point3 *p,int n,point3 *ch)  
{  
	sort(p,p+n);
	int nt=0;
	for(int i=0;i<n;i++)
	{
		if(!nt||!(p[nt-1]==p[i])) p[nt++]=p[i];
	}
	n=nt;
	int m=0;  
	for(int i=0;i<n;i++)  
	{  
		while(m>1&&dcmp(cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]))<=0) --m;  
		ch[m++]=p[i];  
	} 
	int k=m;  
	for(int i=n-2;i>=0;i--)  
	{  
		while(m>k&&dcmp(cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]))<=0) --m;  
		ch[m++]=p[i];  
	}  
	if(n>1) --m;  
	return m;  
}  


int n,m;
double a,b,c,d;
point3 p[105],p0,q[105],ch[105];

int main()
{
	int i,j;
	int at,bt,ct,dt;
	while(scanf("%d %d %d %d",&at,&bt,&ct,&dt)!=EOF&&(at||bt||ct||dt))
	{
		a=at,b=bt,c=ct,d=dt;
		scanf("%d",&n);
		for(i=0;i<n;i++) p[i].read();
		p0.read();
		for(i=0;i<n;i++) p[i]=p[i]-p0;
		d=d-dot(point3(a,b,c),p0);
		scanf("%d",&m);
		for(i=0;i<m;i++) q[i].read(),q[i]=q[i]-p0;
		int nt=0;
		for(i=0;i<n;i++)
		{
			double te=dot(point3(a,b,c),p[i]);
			if(dcmp(te)==0) continue;
			if(dcmp(d/te)>0) p[i]=p[i]*(d/te),++nt;
		}
		if(nt==0) printf("ZERO\n");
		else if(nt<n) printf("INF\n");
		else
		{
			for(i=0;i<n;i++)
			{
				if(ct) p[i].z=0;
				else if(bt) swap(p[i].y,p[i].z),p[i].z=0;
				else swap(p[i].x,p[i].z),p[i].z=0;
			}
			nt=convexhull(p,n,ch);
			int rt=0;
			//for(i=0;i<nt;i++) cout<<ch[i].x<<" "<<ch[i].y<<endl;
			for(i=0;i<m;i++)
			{
				double te=dot(point3(a,b,c),q[i]);
				if(dcmp(te)==0||dcmp(d/te)<0) continue;
				q[i]=q[i]*(d/te);
				if(ct) q[i].z=0;
				else if(bt) swap(q[i].y,q[i].z),q[i].z=0;
				else swap(q[i].x,q[i].z),q[i].z=0;
				//cout<<q[i].x<<" "<<q[i].y<<endl;
				for(j=0;j<nt;j++)
				{
					if(dcmp(cross(q[i]-ch[j],ch[(j+1)%nt]-ch[j]))>=0) break;
				}
				if(j>=nt) {++rt;/*cout<<q[i].x<<" 1 "<<q[i].y<<endl;*/}
			}
			printf("%.2lf%%\n",100.0*rt/m);
		}
		
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值