POJ·Pipe

初见安~这里是传送门:POJ P1039 Pipe

Sol

计算几何的一个入门题目呢。

有一个可能初学不太容易发现的点就是:要这条光线到最远,那么擦边过的一定是最优解【并不是说最优解就只能是擦边过的】,也就是一定过了至少一个上界和一个下界。那不就简单了嘛,两点确定一条直线,我们枚举一个上界点和一个下界点确定一条直线,然后从1~n确认这条直线的合法性以及走到了哪个位置。思路比较好理解。

接下来就是关于实现了,也就是计算几何的硬操作。首先我们要判断这条直线依次经过各个管道的拐点是否有不合法,也就是这条直线在拐点的地方是否高于上界或者低于下界。有两个方法,一个是直接求出直线的解析式看y座标的位置,还有一个【参考代码所用的方法,好像更麻烦一些】就是利用叉积的正负。因为如果这条直线没有超出管道,那么该直线顺时针旋转和逆时针旋转可以分别碰到该拐点的上界和下界,即两个叉积异号【至于是哪两两向量乘出来的两个叉积就自己想吧】。

再来就是如果超出管道了,要求交点的x座标。这个……求两个直线解析式然后一发带走吧。

上代码了。【其实计算几何的话除了基本操作,别的地方的代码都不建议看。写法太多了

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define maxn 50
using namespace std;
typedef long long ll;
typedef long double ld;
const ld eps = 1e-8L;
int read() {
	int x = 0, f = 1, ch = getchar();
	while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
	while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
	return x * f;
}

int n;
struct node {ld x, y;} up[maxn], down[maxn];
int change(ld x) {if(x > eps) return 1; if(x < -eps) return -1; return 0;}//返回正负
ld fun(ld x1, ld y1, ld x2, ld y2) {return x1 * y2 - x2 * y1;}//返回叉积
ld cross(node a, node b, node c) {return fun(b.x - a.x, b.y - a.y, c.x - a.x, c.y - a.y);}//作差一下再扔叉积
ld get_x(node a, node b, node c, node d) {//求两直线交点的x座标
	ld k1, k2, b1, b2;
	k1 = (b.y - a.y) / (b.x - a.x), k2 = (d.y - c.y) / (d.x - c.x);
	b1 = a.y - k1 * a.x, b2 = d.y - k2 * d.x;
	return (b2 - b1) / (k1 - k2);
}

bool check(int i, int j, int k) {return change(cross(up[i], down[j], up[k])) * change(cross(up[i], down[j], down[k])) > 0;}//判定是否超出管道
void solve() {
	ld ans = -1000000000.0;
	for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(i != j) {
		register int k = 1;
		for(k; k <= n; k++) if(check(i, j, k)) break;
		if(k > n) {puts("Through all the pipe."); return;}
		ld tmp = 0.0;
		if(k < max(i, j)) continue;
		tmp = max(get_x(up[i], down[j], up[k], up[k - 1]), get_x(up[i], down[j], down[k], down[k - 1]));
		ans = max(ans, tmp);
	}
	printf("%.2Lf\n", ans);
}
signed main() {
	while(n = read()) {
		if(!n) return 0;
		for(int i = 1; i <= n; i++) scanf("%Lf%Lf", &up[i].x, &up[i].y), down[i].x = up[i].x, down[i].y = up[i].y - 1.0;
		solve();
	}
	return 0;
}

迎评:)
——End——

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章