BZOJ 1007 水平可见直线 | 计算几何

BZOJ 1007 水平可见直线

题面

平面直角坐标系上有一些直线,请求出在纵坐标无限大处能看到哪些直线。

题解

将所有直线按照斜率排序(平行的直线只保留最高的直线),维护一个栈,当当前直线与栈顶直线的交点在栈顶两条直线的交点的左边,则弹出栈顶元素。可以画图证明这是正确的(因为我们要维护一个下凸的图形)。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 50005;
int n, top, idx, ans[N];
struct Line {
    int id;
    double k, b;
    bool operator < (const Line &obj) const{
	return k != obj.k ? k < obj.k: b < obj.b;
    }
} raw[N], line[N], stk[N];
double getx(const Line &A, const Line &B){
    return (B.b - A.b) / (A.k - B.k);
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
	raw[i].id = i, scanf("%lf%lf", &raw[i].k, &raw[i].b);
    sort(raw + 1, raw + n + 1);
    line[idx = 1] = raw[1];
    for(int i = 2; i <= n; i++)
	line[raw[i].k == raw[i - 1].k ? idx: ++idx] = raw[i];
    for(int i = 1; i <= idx; i++){
	while(top > 1 && getx(line[i], stk[top]) <= getx(stk[top], stk[top - 1])) top--;
	stk[++top] = line[i];
    }
    for(int i = 1; i <= top; i++) ans[i] = stk[i].id;
    sort(ans + 1, ans + top + 1);
    for(int i = 1; i <= top; i++) printf("%d ", ans[i]);
    puts("");
    return 0;
}
原文地址:https://www.cnblogs.com/RabbitHu/p/BZOJ1007.html