- Pipe
- 题意
有一个弯形的管道,给出每个上拐点的坐标,起点和终点也视为拐点。下拐点的y坐标是上拐点y坐标-1,x坐标不变,问从管道的左端点射出一条光线,光线能够到达的最远的x坐标是多少?
- 思路
这道题我考虑了极限法,即最远的光线一定经过两个拐点(可能都是上拐点,或者都是下拐点,也可能一个上拐点一个下拐点,当然最远的光线不止一条,但肯定有一条经过两个拐点,可以平移得到),然后枚举两个拐点构成的直线,判断是否合法,如果合法求它能到达的最远的x坐标。如何判断该直线是否与管道相交呢?我是求出相应的y坐标与上下拐点的y坐标进行比较,如果大于最大的或者小于最小的,就是有交叉,然后求出交点的x坐标,更新答案。
#pragma GCC optimize(2)
#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];
double do_x(node a,node b,node c,node d){
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);
return x;
}
double do_y(double x,node a,node b){
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){
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)
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()
{
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;
for(j=i+1;j<=N;j++){
if(all)
break;
do_(i,0,j,0);
do_(i,0,j,1);
}
for(j=i+1;j<=N;j++){
if(all)
break;
do_(i,1,j,0);
do_(i,1,j,1);
}
}
if(all)
prf("Through all the pipe.\n");
else
prf("%.2f\n",res);
}
return 0;
}