poj2826

题意:给你两个线段 填空垂直下雨 问能接到的水的面积

ans = 0.0:

1.存在线段平行y轴

2.两线段重合平行不相交

2.一条线挡住另一条

求S:点到直线的距离 * x / 2 

注:自己加的点虚构的坐标可能和原有的点撞上啊!加个一啊!

 答案最好加eps

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
 
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
 
struct Point{
	double x,y;
	Point(double x = 0,double y = 0) : x(x),y(y) {}
}A1,A2,B1,B2;
typedef Point Vector;
 
struct NODE{
	Point p,q;
}a[1005];

int t;

int dcmp(double x){//equal ?= 0
	if(fabs(x) < eps) return 0;
	else return x < 0 ? -1:1;
}
 
//运算符重载
Vector operator + (Vector A, Vector B){ return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Vector A, Vector B){ return Vector(A.x-B.x, A.y-B.y); }
Vector operator * (Vector A, double p){ return Vector(A.x*p, A.y*p); }
bool operator == (const Point &a, const Point &b){
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}
 
double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; }
double Cross(Vector A, Vector B){ return A.x*B.y - A.y*B.x; }

bool Collinear(Point P1,Point P2,Point P3,Point P4){
	double A = Cross(P1 - P2,P3 - P2);
	double B = Cross(P1 - P2,P4 - P2);
	if(!dcmp(A) && !dcmp(B)) return 1;
	return 0;
}
 
//判断平行
bool Parallel(Point P1,Point P2,Point P3,Point P4){
	if(dcmp(Cross(P1 - P2,P3 - P4)) == 0) return 1;
	return 0;
}

//P点再P1P2上 叉积==0
bool OnSeg(Point P,Point P1,Point P2){
	return dcmp(Cross(P1 - P,P2 - P)) == 0 && dcmp(Dot(P1 - P,P2 - P)) <= 0;
}

//?相交
bool check(Point P1,Point P2,Point P3,Point P4){//原线段&线段 注直线&线段
	//端点在线上 非规范相交
	if(OnSeg(P1,P3,P4)) return 1;
	if(OnSeg(P2,P3,P4)) return 1;
	if(OnSeg(P3,P1,P2)) return 1;
	if(OnSeg(P4,P1,P2)) return 1;
	//跨立实验规范相交
	double _A = Cross(P1 - P2,P3 - P2);
	double _B = Cross(P1 - P2,P4 - P2);
	double _C = Cross(P3 - P4,P1 - P4);
	double _D = Cross(P3 - P4,P2 - P4);
	return dcmp(_A) * dcmp(_B) < 0 && dcmp(_C) * dcmp(_D) < 0;//=0重合或平行
}

//一般法求交点
Point Ist(Point P1,Point P2,Point P3,Point P4){
	Point ist;
	ist.x = inf * 1.0;
	ist.y = inf * 1.0;
	double a1 = 1.0 *(P1.y - P2.y);
	double b1 = 1.0 *(P2.x - P1.x);
	double c1 = 1.0 *(P1.x * P2.y - P2.x * P1.y);
	double a2 = 1.0 *(P3.y - P4.y);
	double b2 = 1.0 *(P4.x - P3.x);
	double c2 = 1.0 *(P3.x * P4.y - P4.x * P3.y);
 
	double pd = a2 * b1 - a1 * b2;
	if(dcmp(pd) == 0) return ist;//无解
	ist.x = (c1 * b2 - c2 * b1) / pd;
	ist.y = (a2 * c1 - a1 * c2) / (-1.0 * pd);
	return ist;
}
 
//两参数方程求交点,(点,向量,点,向量)
Point Getlinenode(Point P,Point v,Point Q,Point w){
	//线1(P1,P2) 线2(P3,P4) (P1,P1-P2,P3,P3-P4)
    Point u = P - Q;
    double t = Cross(w,u) / Cross(v,w);
    return P + v * t;
}

double Length(Vector A){return sqrt(Dot(A,A));}//计算向量的长度
double DistanceToSegment(Point P,Point A,Point B){
    if(A==B)return Length(P-A);
    Vector v1=B-A,v2=P-A,v3=P-B;
//	if(dcmp(Dot(v1,v2))<0)return Length(v2);     //第二类第一小类 PA
//	else if(dcmp(Dot(v1,v3))>0)return Length(v3);//第二类第二小类 PB
    return fabs(Cross(v1,v2))/Length(v1);//垂线长度
}

int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%lf %lf %lf %lf",&A1.x,&A1.y,&A2.x,&A2.y);
		scanf("%lf %lf %lf %lf",&B1.x,&B1.y,&B2.x,&B2.y);
		if(Collinear(A1,A2,B1,B2) || Parallel(A1,A2,B1,B2) || A1.y == A2.y || B1.y == B2.y || !check(A1,A2,B1,B2)){//两条线平行重合 || 线垂直 || 两线段不相交
			printf("0.00\n");
			continue;
		}
		if(A1.y < A2.y) swap(A1,A2);
		if(B1.y < B2.y) swap(B1,B2);
		if(A1.y < B1.y){
			swap(A1,B1);
			swap(A2,B2);
		}//1 > 2   A > B
		Point O = Ist(A1,A2,B1,B2);
		Point C;
		C.x = B1.x;
		C.y = A1.y;
		//B1C - A1A2 B1C垂直x轴
		Point F = Ist(B1,C,A1,A2);
//		cout << F.x << "#" << F.y << endl;
//		cout << A1.y << "@" << B1.y << endl;
		if(F.y <= A1.y && F.y >= B1.y){
			printf("0.00\n");
			continue;
		}
		Point AB;
		AB.y = B1.y;
		AB.x = B1.x + 1;
//		cout << AB.x << "$" << AB.y << endl;
		Point AA1 = Ist(AB,B1,A1,A2);//AA1-B1  O
		double h = DistanceToSegment(O,AA1,B1);
		printf("%.2f\n",h * fabs(B1.x - AA1.x) / 2 + eps);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值