A . 梦想成为天文学家
这道题是一个原题,我们要用向量的知识来解决它,求解的就是四点共面。
//四个点三个向量 构成一个行列式 行列式的结果为0则共面否则不共面
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct p{
int x,y,z;
}P[5];
p s[5];
int main()
{
int t,cnt=0;
scanf("%d",&t);
while(t--){
for(int i=1;i<=4;i++)
{
scanf("%d %d %d",&P[i].x,&P[i].y,&P[i].z);
}
s[1].x=P[2].x-P[1].x;
s[1].y=P[2].y-P[1].y;
s[1].z=P[2].z-P[1].z;
s[2].x=P[3].x-P[1].x;
s[2].y=P[3].y-P[1].y;
s[2].z=P[3].z-P[1].z;
s[3].x=P[4].x-P[1].x;
s[3].y=P[4].y-P[1].y;
s[3].z=P[4].z-P[1].z;
int ans;
ans=s[1].x*s[2].y*s[3].z+s[2].x*s[3].y*s[1].z+s[1].y*s[2].z*s[3].x-s[3].x*s[2].y*s[1].z-s[2].x*s[1].y*s[3].z-s[1].x*s[2].z*s[3].y;
if(ans==0){
cout<<"Day #"<<++cnt<<": "<<"Yes"<<endl;
}
else{
cout<<"Day #"<<++cnt<<": "<<"No"<<endl;
}
}
return 0;
}
B 线段的投影
这道题是一个二维几何的题目,要求解的多线段是否在同一条直线上的投影互相之间至少有一个交点。
其实两个线段必定可以找一个角度使得其投影在直线上有交点,所以我们就可以通过枚举两个线段的端点所构成直线的方式来判断,如果枚举一条直线可以与所有线段相交,即可证明所有的线段可以在同一条直线上的投影有公共点。
特判:
只有一个点或两个点时,一定可以找到一条直线。
还有就是对于枚举的点 两点距离小于1e-8 的点可以看成同一点不必枚举。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps = 1e-8;
int sgn(double x){
if(fabs(x)<eps)return 0;
if(x<0)return -1;
else return 1;
}
struct Point {
double x,y;
Point (){};
Point (double _x,double _y){
x=_x,y=_y;
}
void input(){
scanf("%lf%lf",&x,&y);
}
Point operator - (const Point &b)const{
return Point (x-b.x,y-b.y);
}
double operator ^ (const Point &b)const{
return x*b.y-y*b.x;
}
double distance (Point p){
return hypot(x-p.x,y-p.y);
}
};
struct Line{
Point s,e;
Line(){};
Line(Point _s,Point _e){
s=_s;e=_e;
}
void input(){
s.input();
e.input();
}
int line_cross_seg(Line v){
int d1 = sgn((e-s)^(v.s-s));
int d2 = sgn((e-s)^(v.e-s));
if((d1^d2) == -2)return 2;
return (d1==0||d2==0);
}
};
Line l[110];
bool judge(Line v,int n){
for(int i=0;i<n;i++){
//cout<<v.line_cross_seg(l[i])<<endl;
if(v.line_cross_seg(l[i])==0)return false;
}
return true;
}
int main(){
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++){
l[i].input();
}
if(n==1){
printf("Yes!\n");
continue;
}
int flag=0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
bool ans1,ans2,ans3,ans4;
if(l[i].s.distance(l[j].s)>eps)
ans1=judge(Line(l[i].s,l[j].s),n);
if(l[i].s.distance(l[j].e)>eps)
ans2=judge(Line(l[i].s,l[j].e),n);
if(l[i].e.distance(l[j].s)>eps)
ans3=judge(Line(l[i].e,l[j].s),n);
if(l[i].e.distance(l[j].e)>eps)
ans4=judge(Line(l[i].e,l[j].e),n);
//cout<<ans1<<ans2<<ans3<<ans4<<endl;
if(ans1||ans2||ans3||ans4){
flag=1;
break;
}
if(flag)break;
}
}
if(flag)printf("Yes!\n");
else printf("No!\n");
}
return 0;
}
C叉乘来了。
简单的叉乘求法向量
#include<iostream>
#include<cstdio>
using namespace std;
struct point{
double x,y,z;
point(){};
point(double _x,double _y,double _z){
x=_x;
y=_y;
z=_z;
}
void input(){
scanf("%lf%lf%lf",&x,&y,&z);
}
void output(){
printf("%.2lf %.2lf %.2lf\n",x,y,z);
}
point operator ^ (const point &b)const{
return point (y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);
}
};
int main(){
point a,b,c;
a.input();
b.input();
c=a^b;
c.output();
}