HNOI 2008 水平可见直线

                      HNOI 2008 水平可见直线

在 xoy 直角坐标平面上有n条直线 L1,L2,...,Ln,若在y 值为正无穷大处往下看,能见到 Li的某个子线段,则称 Li为可见的,否则 Li为被遮盖的。 
例如,对于直线 
L1:y=x; L2:y=-x; L3:y=0 
则 L1和L2是可见的,L3是被遮盖的。 
给出 n 条直线,表示成 y=Ax+B 的形式(|A|,|B|<=500000),且 n 条直线两两不重合。求出所有可见的直线。

第一行为 n(0<n<50000),接下来 n行输入 Ai,Bi。 

从小到大输出可见直线的编号,两两中间用空格隔开。 


-1 0 
1 0 
0 0

1 2 

n<50000



本题题解三部曲:

一部曲:以k为第一关键字,b为第二关键字,进行排序。

二部曲:构建关于直线的单调栈。

三部曲:整理并输出答案。

就这么简单。


#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 50000 + 5
int n, s[N], t[N];
struct LINE
{
	int num;
	double k, b; 
	void init(int i)
	{
		scanf("%lf%lf", &k, &b);
		num = i;
	}
	bool operator < (const LINE a) const
	{
		return k < a.k || (k == a.k && b > a.b);
	}
}h[N];
void begin()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++)
		h[i].init(i);
	sort(h + 1, h + n + 1);
}
double dotx(LINE u, LINE v)
{
	return (u.b - v.b) / (v.k - u.k);
}
void work()
{
	s[0] = s[1] = 1;
	for (int i = 2; i <= n; i ++)
	{
		if (h[i].k == h[i - 1].k) continue;
		while (s[0] > 1 && dotx(h[s[s[0] - 1]], h[i]) <= dotx(h[s[s[0] - 1]], h[s[s[0]]]))
			s[0] --;
		s[++ s[0]] = i;
	}
	for (int i = 1; i <= s[0]; i ++)
		t[i] = h[s[i]].num;
	sort(t + 1, t + s[0] + 1);
}
void end()
{
	for (int i = 1; i <= s[0]; i ++)
		printf("%d ", t[i]);
}
int main()
{
	begin();
	work();
	end();
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值