POJ 1039

一条直线,必定可以通过旋转和平移使得它和一个上顶点一下顶点相切,这样的直线是最优的。因为这样能确定了直线所能到达的最远X。这样的两个顶点就规定了它的上下界,

所以,枚举上下顶点,注意判断是否能到达入口处。只需判断直线是否与每个横切面的直线都有相交。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;
const double eps=0.00000001;
struct point{
	double x,y;
}up[30],dp[30];
struct edge{
	point start,end;
}Line;
int n;
double longest;

int dpcmp(double h){
	if(fabs(h)<eps) return 0;
	return h>0?1:-1;
}

bool cross(point a,point b,point c,point d){
	double h=(c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x);
	double j=(d.x-a.x)*(b.y-a.y)-(d.y-a.y)*(b.x-a.x);
	int s1=dpcmp(h); int s2=dpcmp(j);
	if(s1*s2<0)
	return true;
	else if(s1*s2==0){
		return true;
	}
	return false;
}


bool slove(int uper, int down){
	int i;
	for(i=0;i<n;i++)
		if(!cross(Line.start,Line.end,up[i],dp[i])) break;
		if(i>=n) {
			return true;
		}
		else if(i<max(uper,down)) return false;
		else{
			double x1=-90080000,x2=-90080000;
			double k1=(Line.end.y-Line.start.y)/(Line.end.x-Line.start.x);
			double k2=(up[i].y-up[i-1].y)/(up[i].x-up[i-1].x);
			double k3=(dp[i].y-dp[i-1].y)/(dp[i].x-dp[i-1].x);
			if(cross(Line.start,Line.end,up[i-1],up[i]))
			x1=(up[i].y-Line.end.y+k1*Line.end.x-k2*up[i].x)/(k1-k2);
			if(cross(Line.start,Line.end,dp[i-1],dp[i]))
			x2=(dp[i].y-Line.end.y+k1*Line.end.x-k3*dp[i].x)/(k1-k3);
			longest=max(longest,max(x1,x2));
			return false;
		}
}

int main(){
	while(scanf("%d",&n)!=EOF){
		if(n==0) break;
		longest=-90080000;
		for(int i=0;i<n;i++){
			scanf("%lf%lf",&up[i].x,&up[i].y);
			dp[i]=up[i]; dp[i].y=dp[i].y-1;
		}
		bool flag=false;
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++)
			if(i!=j){
				Line.start=up[i]; Line.end=dp[j];
				if(slove(i,j)){
					flag=true;
					break;
				}
			}
			if(flag)
			break;
		}
		if(flag) printf("Through all the pipe.\n");
		else printf("%.2f\n",longest);
	}
	return 0;
}

  

转载于:https://www.cnblogs.com/jie-dcai/p/3872814.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值