POJ Pipe (几何)

  • Pipe
  • 题意
    有一个弯形的管道,给出每个上拐点的坐标,起点和终点也视为拐点。下拐点的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