poj 2826
来源:互联网 发布:软件测试需要会什么 编辑:程序博客网 时间:2024/05/17 22:15
题目概述
在二维平面中,将两块直木板的某个位置钉起来装雨水,雨水从y轴正方向向下落下,给出木板四个端点的坐标,且木板可视为线段,问钉成的木板装满水时雨水的横截面积
时限
1000ms/3000ms
输入
第一行正整数N,代表数据组数,第二行四个整数,描述第一块木板端点坐标,第三行四个整数,描述第二块木板端点坐标,两组中间会有一个空行
限制
坐标绝对值<=10000
输出
每行一个数,所求横截面积,保留2位小数
样例输入
2
0 1 1 0
1 0 2 1
0 1 2 1
1 0 1 2
样例输出
1.00
0.00
讨论
计算几何,非常复杂,需要充分讨论所有可能的情况,虽然输入都是整数,但是最好直接当浮点数处理,整体思路是先确定相交情况,然后排除掉横截面积必然为0的情况,比如角度非正,线段在同一象限但是上面的完全挡住下面的,之后确定交点,确定能接水的三角形的边的端点位置,然后求出面积,具体都会体现在代码中,这里不过多解释
代码看着长,实际上冗余度很大,但是实在懒得修改了
题解状态
220K,16MS,C++,6837B
题解代码
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;#define INF 0x3f3f3f3f #define MAXN 53#define memset0(a) memset(a,0,sizeof(a))#define EPS 1e-6const double pi = atan(1.0) * 4;//pi值 留作备用double dp(double x1, double y1, double x2, double y2, double x3, double y3)//dot_product 数量积 以第二个点为公共起点{ return (x1 - x2)*(x3 - x2) + (y1 - y2)*(y3 - y2);}double xp(double x1, double y1, double x2, double y2, double x3, double y3)//cross_product 向量积 以第二个点为公共起点{ return (x1 - x2)*(y3 - y2) - (y1 - y2)*(x3 - x2);}double projx(double x1, double y1, double x2, double y2)//projection_on_x_axis 在x轴射影 以第一个点为起点{ return abs(dp(x2, y2, x1, y1, x1 + 1, y1));}double projy(double x1, double y1, double x2, double y2)//projection_on_y_axis 在y轴射影 以第一个点为起点{ return abs(dp(x2, y2, x1, y1, x1, y1 + 1));}int quadrant(double a)//象限 参数是角度 在轴上会返回0{ if (0 < a&&a < 90) return 1; if (90 < a&&a < 180) return 2; if (-180 < a&&a < -90) return 3; if (-90 < a&&a < 0) return 4; else return 0;}bool onsegment(double x, double y, double x1, double y1, double x2, double y2)//快速排斥实验 以后两个点构成矩形{ return min(x1, x2) <= x&&x <= max(x1, x2) && min(y1, y2) <= y&&y <= max(y1, y2);}int intersect(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)//相交 输入是所有四个点的坐标{ double xp1 = xp(x3, y3, x1, y1, x2, y2); double xp2 = xp(x4, y4, x1, y1, x2, y2); double xp3 = xp(x1, y1, x3, y3, x4, y4); double xp4 = xp(x2, y2, x3, y3, x4, y4); if (xp1*xp2 < 0 && xp3*xp4 < 0) return 5;//最普通的X形相交 返回5 int ans = 0; if (abs(xp1) < EPS&&onsegment(x3, y3, x1, y1, x2, y2)) ans++;//T型相交 有1个点在另一条线段上 返回1 if (abs(xp2) < EPS&&onsegment(x4, y4, x1, y1, x2, y2)) ans++;//V型相交 有2个点在另一条线段上 返回2 if (abs(xp3) < EPS&&onsegment(x1, y1, x3, y3, x4, y4)) ans++;//不完全重合 两条线段有一端重合 另一端共线 有3个点在另一条线段上 返回3 if (abs(xp4) < EPS&&onsegment(x2, y2, x3, y3, x4, y4)) ans++;//完全重合 返回4 return ans;//如果不相交 则返回0}double dis(double x1, double y1, double x2, double y2)//distance 两点间距离{ return sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));}double angle(double x1, double y1, double x2, double y2)//角度 利用数量积求出余弦值 进而求出角度 顺便判断正负{ double a = acos(dp(x2, y2, x1, y1, x1 + 1, y1) / dis(x1, y1, x2, y2)) * 180 / pi; return y2 > y1 ? a : -a;}double area(double x1, double y1, double x, double y, double x2, double y2)//面积 用底乘高除二算{ return abs(x1 - x2)*projy(x, y, x2, y2) / 2;}double fun(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4){ int intersection = intersect(x1, y1, x2, y2, x3, y3, x4, y4);//判断相交情况 if (!intersection) { return 0;//不相交返回0 } else if (intersection == 1) {//T型相交 double poix, poiy, ox1, oy1, ox2, oy2;//point_of_intersection_x point_of_intersection_y 交点坐标 后面四个是交点上方的两个点的坐标 o只是为了区别一下而已 double xp1 = xp(x3, y3, x1, y1, x2, y2); double xp2 = xp(x4, y4, x1, y1, x2, y2); double xp3 = xp(x1, y1, x3, y3, x4, y4); double xp4 = xp(x2, y2, x3, y3, x4, y4);//重新计算四个向量积 有点多余 if (abs(xp1) < EPS) { poix = x3, poiy = y3; ox1 = x4, oy1 = y4; if (y1 > y2) oy2 = y1, ox2 = x1; else oy2 = y2, ox2 = x2; } else if (abs(xp2) < EPS) { poix = x4, poiy = y4; ox1 = x3, oy1 = y3; if (y1 > y2) oy2 = y1, ox2 = x1; else oy2 = y2, ox2 = x2; } else if (abs(xp3) < EPS) { poix = x1, poiy = y1; ox1 = x2, oy1 = y2; if (y3 > y4) oy2 = y3, ox2 = x3; else oy2 = y4, ox2 = x4; } else if (abs(xp4) < EPS) {//以唯一一个为0的向量积确定哪个点在另一条线段上 将这条线段上另一个点记为点o1 对于另一条线段 取y值较大者作为点o2 poix = x2, poiy = y2; ox1 = x1, oy1 = y1; if (y3 > y4) oy2 = y3, ox2 = x3; else oy2 = y4, ox2 = x4; } if (oy1 < oy2) {//为方便处理 令点o1为y值较大者 swap(ox1, ox2); swap(oy1, oy2); } double theta1 = angle(poix, poiy, ox1, oy1), theta2 = angle(poix, poiy, ox2, oy2);//求交点poi和点o1,o2的角度 if (theta1 < EPS || theta2 < EPS) return 0;//如果有负的 肯定是0 if (quadrant(theta1) == quadrant(theta2)) {//对于同象限需要进一步讨论 if (((quadrant(theta1) == 1 && theta2<theta1) || (quadrant(theta1) == 2 && theta2>theta1)) && projx(poix, poiy, ox1, oy1) >= projx(poix, poiy, ox2, oy2)) return 0;//如果同象限 并且在上方的一条在x轴投影较大 就会把下面的挡住 else { double poi2y = oy2, poi2x = (poi2y - poiy) / (oy1 - poiy)*(ox1 - poix) + poix;//过较低的点o2做水平线交o1于poi2 return area(poi2x, poi2y, poix, poiy, ox2, oy2);//求三角形poi,poi2,o2的面积 } } else { double poi2y = oy2, poi2x = (poi2y - poiy) / (oy1 - poiy)*(ox1 - poix) + poix; return area(poi2x, poi2y, poix, poiy, ox2, oy2);//求面积 } } else if (intersection == 2) {//V型相交 double poix, poiy, ox1, oy1, ox2, oy2; if (abs(x1 - x3) < EPS&&abs(y1 - y3) < EPS) { poix = x1, poiy = y1; ox1 = x2, oy1 = y2, ox2 = x4, oy2 = y4; } else if (abs(x1 - x4) < EPS&&abs(y1 - y4) < EPS) { poix = x1, poiy = y1; ox1 = x2, oy1 = y2, ox2 = x3, oy2 = y3; } else if (abs(x2 - x3) < EPS&&abs(y2 - y3) < EPS) { poix = x2, poiy = y2; ox1 = x1, oy1 = y1, ox2 = x4, oy2 = y4; } else if (abs(x2 - x4) < EPS&&abs(y2 - y4) < EPS) { poix = x2, poiy = y2; ox1 = x1, oy1 = y1, ox2 = x3, oy2 = y3; }//差不多的原理找出交点poi和另外两个点o1,o2 else { return 0; }//但会有些特殊情况 比如一条线段完全被包含在另一条线段里 交点也是2 但无一例外返回0 if (oy1 < oy2) {//下面的处理就完全一样了 swap(ox1, ox2); swap(oy1, oy2); } double theta1 = angle(poix, poiy, ox1, oy1), theta2 = angle(poix, poiy, ox2, oy2); if (theta1 < EPS || theta2 < EPS) return 0; if (quadrant(theta1) == quadrant(theta2)) { if (((quadrant(theta1) == 1 && theta2<theta1) || (quadrant(theta1) == 2 && theta2>theta1)) && projx(poix, poiy, ox1, oy1) >= projx(poix, poiy, ox2, oy2)) return 0; else { double poi2y = oy2, poi2x = (poi2y - poiy) / (oy1 - poiy)*(ox1 - poix) + poix; return area(poi2x, poi2y, poix, poiy, ox2, oy2); } } else { double poi2y = oy2, poi2x = (poi2y - poiy) / (oy1 - poiy)*(ox1 - poix) + poix; return area(poi2x, poi2y, poix, poiy, ox2, oy2); } } else if (intersection == 5) {//X型相交 double poix, poiy, ox1, oy1, ox2, oy2; if (abs(x1 - x2) < EPS) { double k3 = (y4 - y3) / (x4 - x3); poix = x1, poiy = k3*(x1 - x3) + y3; } else if (abs(x3 - x4) < EPS) { double k1 = (y2 - y1) / (x2 - x1); poix = x3, poiy = k1*(x3 - x1) + y1; } else { double k1 = (y2 - y1) / (x2 - x1); double k3 = (y4 - y3) / (x4 - x3); poix = (y3 - y1 + k1*x1 - k3*x3) / (k1 - k3), poiy = (k1*k3*(x3 - x1) + k3*y1 - k1*y3) / (k3 - k1); }//利用点斜式方程求出交点 从poj 1269搬来的部分源码 if (y1 > y2) oy1 = y1, ox1 = x1; else oy1 = y2, ox1 = x2; if (y3 > y4) oy2 = y3, ox2 = x3; else oy2 = y4, ox2 = x4; if (oy1 < oy2) {//下面也是一样的 swap(ox1, ox2); swap(oy1, oy2); } double theta1 = angle(poix, poiy, ox1, oy1), theta2 = angle(poix, poiy, ox2, oy2); if (theta1 < EPS || theta2 < EPS) return 0; if (quadrant(theta1) == quadrant(theta2)) { if (((quadrant(theta1) == 1 && theta2<theta1) || (quadrant(theta1) == 2 && theta2>theta1)) && projx(poix, poiy, ox1, oy1) >= projx(poix, poiy, ox2, oy2)) return 0; else { double poi2y = oy2, poi2x = (poi2y - poiy) / (oy1 - poiy)*(ox1 - poix) + poix; return area(poi2x, poi2y, poix, poiy, ox2, oy2); } } else { double poi2y = oy2, poi2x = (poi2y - poiy) / (oy1 - poiy)*(ox1 - poix) + poix; return area(poi2x, poi2y, poix, poiy, ox2, oy2); } } else { return 0;//对于各种重合 统统返回0 }}int main(void){ //freopen("vs_cin.txt", "r", stdin); //freopen("vs_cout.txt", "w", stdout); int times; scanf("%d", ×);//input while (times--) { double x1, y1, x2, y2, x3, y3, x4, y4; scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4);//input printf("%.2lf\n", fun(x1, y1, x2, y2, x3, y3, x4, y4));//output }}
EOF
0 0
- poj 2826
- poj 2826
- poj 2826 Easy Problem
- poj 2826 几何
- POJ 2826 (计算几何)
- poj 2826 计算几何
- POJ
- poj
- POJ
- POJ
- poj
- poj
- POJ
- POJ
- poj
- POJ
- POJ
- POJ
- Unix环境高级编程笔记
- Linux 下的 shell 编程之 输入输出
- UICollectionView Class Reference
- 怎样在配置页面加配置项
- Android启动Activity中间黑屏
- poj 2826
- ssh无密码登录设置错误
- opencv在MAC下的安装
- 基于AFN 3.0 封装(包括图片与视频的表单上传)
- HDU 3400 Line belt
- ios 利用 NSURLSession下载图片
- CGI
- 粤嵌实验室 26-利用WebView浏览网页
- WEB-INF\classes 为空 The value for the useBean class attribute xxx is invalid