Труба POJ (геометрия)

  • Труба
  • Смысл вопроса
    - изогнутая труба, даны координаты каждой верхней точки перегиба, а начальная и конечная точки также считаются точками перегиба. Координата Y нижней точки перегиба - это координата Y верхней точки перегиба -1, а координата x остается неизменной. Когда луч исходит из левого конца трубы, какова самая дальняя координата x, которую может достичь луч?
  • Размышляя над
    этим вопросом, я рассмотрел метод пределов, то есть самый дальний свет должен проходить через две точки перегиба (могут быть обе верхние точки перегиба или обе нижние точки перегиба, или одна верхняя точка перегиба и одна нижняя точка перегиба, конечно, самый дальний свет больше единицы. Но должна быть линия, которая проходит через две точки перегиба, что можно получить путем перевода), а затем перечислить прямую, образованную двумя точками перегиба, чтобы определить, является ли это законным. Если это допустимо, найдите самую дальнюю координату x, которую она может достичь. Как определить, пересекает ли линия трубу? Я нахожу соответствующую координату y и сравниваю ее с координатой y верхней и нижней точек перегиба. Если она больше максимума или меньше минимума, существует пересечение, а затем нахожу координату x пересечения и обновляю ответ.
#pragma GCC optimize(2)
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
using namespace std;

typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second
#define scf scanf
#define prf printf
typedef pair<ll,ll> pa;
const int dir_4[4][2]={
    
    -1,0,0,1,1,0,0,-1};
const int dir_8[8][2]={
    
    -1,-1,-1,0,-1,1,0,1,1,1,1,0,1,-1,0,-1};
const ll INF=0x3f3f3f3f3f3f3f3f;
const int MAX_N=50;
bool all;
const double eps=1e-8;
double res;
int N;
struct node{
    
    
	double x,y;
}pos[2][MAX_N];//pos[0][]存的是上界的拐点,pos[1][]存的是下界的拐点 
double do_x(node a,node b,node c,node d){
    
    //求能够到达的最大的x 
	double a1,b1,c1,a2,b2,c2;
	a1=b.y-a.y;a2=d.y-c.y;
	b1=a.x-b.x;b2=c.x-d.x;
	c1=b.x*a.y-a.x*b.y;c2=d.x*c.y-c.x*d.y;
	double x=(b1*c2-b2*c1)/(b2*a1-b1*a2);//除数是不可能为0的,不存在平行 
	return x;
}
double do_y(double x,node a,node b){
    
    //求直线在x的y坐标 
	double y=a.y-(a.x-x)*(b.y-a.y)/(b.x-a.x);
	return y;
}
void do_(int pre,int bk_p,int nex,int bk_n){
    
    
	int i,j,k;
	int du=-1,flag=-1;
	for(i=1;i<=N;i++){
    
    
		double y=do_y(pos[0][i].x,pos[bk_p][pre],pos[bk_n][nex]);
		if(y>pos[0][i].y&&fabs(y-pos[0][i].y)>eps){
    
    //一开始没有加eps,被卡精度了 
			du=i;
			flag=0;
			break;
		}
		if(y<pos[1][i].y&&fabs(y-pos[1][i].y)>eps){
    
    
			du=i; 
			flag=1;
			break;
		}
	}
	if(du==-1){
    
    //与所有的管道上下界都没有交叉,通过整个管道 
		all=1;
		return ;
	}
	if(du<=nex)//交叉部分在这nex之前,直接return
	return ;
	if(!flag)//与管道的上界交叉 
	res=max(res,do_x(pos[bk_p][pre],pos[bk_n][nex],pos[0][i-1],pos[0][i]));
	else // 与管道的下界交叉 
	res=max(res,do_x(pos[bk_p][pre],pos[bk_n][nex],pos[1][i-1],pos[1][i]));
	return ;
} 
int main()
{
    
    
//  freopen(".../.txt","w",stdout);
//  freopen(".../.txt","r",stdin);
//	ios::sync_with_stdio(false);
	while(scf("%d",&N)&&N){
    
    
		int i,j,k;
		double x,y;
		all=0;
		for(i=1;i<=N;i++){
    
    
			scf("%lf %lf",&pos[0][i].x,&pos[0][i].y);
			pos[1][i].x=pos[0][i].x;
			pos[1][i].y=pos[0][i].y-1;
		}
		res=pos[0][1].x;
		for(i=1;i<N;i++){
    
    //枚举该光线上的左拐点 
			if(all)
			break;
			//pre是上界的拐点
			for(j=i+1;j<=N;j++){
    
    // 枚举该光线上的右拐点 
				if(all)
				break;
				//nex是上界的点
				do_(i,0,j,0);					
				//nex是下jie的点
			 	do_(i,0,j,1);
			} 
			//pre是下jie的点
			for(j=i+1;j<=N;j++){
    
    //枚举该光线上的右拐点 
				if(all)
				break;
				//nex是上界的点
				do_(i,1,j,0);
				//nex是下jie的点
				do_(i,1,j,1);
			}
		}
		if(all)
		prf("Through all the pipe.\n");
		else
		prf("%.2f\n",res);
	}
	return 0;
}

рекомендация

отblog.csdn.net/weixin_43311695/article/details/109158203