关闭

bzoj 1007: [HNOI2008]水平可见直线(模拟栈)

标签: 几何算法
469人阅读 评论(0) 收藏 举报
分类:

http://www.lydsy.com/JudgeOnline/problem.php?id=1007

1007: [HNOI2008]水平可见直线

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 7644  Solved: 2922
[Submit][Status][Discuss]

Description

  在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条直线两两不重合.求出所有可见的直线.

Input

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

Output

  从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2
【解析】:

用数组模拟栈,先按斜率排序。

其实最后看到的是一个碗,所以,斜率是递增的,如果存在斜率相等的,在下方的直接舍去。

交点的x坐标也是递增的。

所以,如果当前加入的直线,与栈顶直线的交点x<栈顶与栈中第二直线交点x,则覆盖上一条直线

否则,这条直线加入栈

最后把栈中的直线编号按顺序输出即可。

【代码】:

#include <stdio.h>
#include <stdlib.h>  
#include <string.h>  
#include <algorithm> 
using namespace std;
struct line{//存直线
	double a,b;
	int dex;
}l[52020],s[52020];//l存直线,s模拟栈 
int n,ans[52020];
bool cmp(line l1,line l2)//按斜率从小到大排序
{
	if(l1.a==l2.a)return l1.b>l2.b;
	return l1.a<l2.a;
}
double getx(line l1,line l2)//求两直线交点的x坐标 
{
	return (l2.b-l1.b)/(l1.a-l2.a);
}
void output(int top)//输出 
{
	memset(ans,0,sizeof(ans));
	for(int i=1;i<=top;i++)
		ans[i]=s[i].dex;
	sort(ans+1,ans+1+top);
	for(int i=1;i<=top;i++)
		printf("%d ",ans[i]);
	puts("");
}
void solve()
{
	int top=0;//s的下标
	s[++top]=l[1];
	for(int i=2;i<=n;i++)//遍历直线
	{
		if(l[i].a==l[i-1].a)continue;//会被覆盖
		while(top>1&&getx(l[i],s[top])<getx(s[top],s[top-1]))top--;//可以覆盖上一条直线 
		s[++top]=l[i];
	}
	output(top);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lf%lf",&l[i].a,&l[i].b);
		l[i].dex=i;
	}
	sort(l+1,l+1+n,cmp);
	solve();
}


0
0
查看评论

【bzoj1007】[HNOI2008]水平可见直线 单调栈

Description在xoy直角坐标平面上有n条直线L1,L2,…Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的. 例如,对于直线: L1:y=x; L2:y=-x; L3:y=0 则L1和L2是可见的,L3是被覆盖的....
  • LOI_DQS
  • LOI_DQS
  • 2015-10-23 17:29
  • 1350

【计算几何】[HNOI2008][HYSBZ/BZOJ1007]水平可见直线

题目链接分析如果两条直线斜率相等,显然,截距较小的那一条无论如何都不可见,删掉它们。 我们可以将剩下直线按照斜率的数值从小到大排序。 假设第i条直线是可见的,然后,我们从第i+1条开始向后枚举,分别计算这条直线(设为第j条)和第i条直线交点的横坐标,记作xi,jx_{i,j}。 若xi,k≤x...
  • outer_form
  • outer_form
  • 2016-02-02 14:08
  • 869

BZOJ 1007: [HNOI2008]水平可见直线 题解

(传送门) 其实这道题的求法和凸包类似,首先如果有三条直线i,j,t;并存在 那么如果出现i与j的交点在i与t的交点的左边,那么说明j已经被i和t所覆盖了,用单调栈,把j弹出栈,周而复始。然后……好像也没什么可说的。
  • try__jhf
  • try__jhf
  • 2017-07-13 19:14
  • 68

bzoj 1007 [HNOI2008] 水平可见直线 题解

【原题】 1007: [HNOI2008]水平可见直线 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2961  Solved: 1049 [Submit][Stat...
  • u013724185
  • u013724185
  • 2014-04-16 21:04
  • 1168

[BZOJ 1007][HNOI2008]水平可见直线:单调栈

点击这里查看原题最终得到的一定是一个下凸壳,因此把所有直线以k升序为第一关键字,b降序为第二关键字进行排序。若当前直线能完全覆盖栈顶直线,即i与s[top]的交点在s[top]与s[top-1]的交点左侧,则将栈顶元素弹出。/* User:Small Language:C++ Problem No....
  • SmallSXJ
  • SmallSXJ
  • 2017-04-17 08:09
  • 130

[BZOJ 1007] [HNOI2008]水平可见直线

http://www.lydsy.com/JudgeOnline/problem.php?id=1007题意:略思路:容易想到最后的可见直线会围成个开口向上的半个凸包,所以我们可以先把直线汗斜率排序(凸包的边从左到右斜率递增),再将斜率最小的两条线入栈,然后依次处理每条线,如果其与栈顶元素的交点在上...
  • AcmHonor
  • AcmHonor
  • 2015-12-10 13:31
  • 243

D 1007: [HNOI2008]水平可见直线(栈)

Description  在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.     例如,对于直线:     L1:y=x; L2:y=-x;...
  • thy0311
  • thy0311
  • 2015-05-01 12:59
  • 149

bzoj。 1007: [HNOI2008]水平可见直线

1007: [HNOI2008]水平可见直线 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 8043  Solved: 3060 [Submit][Status][...
  • zzcblogs
  • zzcblogs
  • 2017-11-30 22:09
  • 58

BZOJ 1007: [HNOI2008]水平可见直线

这题应该可以算是一道半平面交的入门铺垫题(阉割版),因为每条直线确定的平面都位于其上方,所以免去了向量的麻烦。具体方法就是先按照斜率排序,判断新加入的直线与栈顶直线交点是否在之前的栈顶与栈顶下面的直线交点的左侧,如果在左侧就弹掉栈顶。多条斜率相同的直线则取b最大的一个。#include<cst...
  • LZJ209
  • LZJ209
  • 2017-01-12 10:13
  • 232

BZOJ 1007: [HNOI2008]水平可见直线 几何

按斜率排序,斜率线相同的直线取截距最大的 一条直线能够被看到的条件是,与比它斜率小的交点在比它斜率大的交点的左侧 1007: [HNOI2008]水平可见直线 Time Limit: 1 Sec  Memory Limit: 162 MB Su...
  • u012797220
  • u012797220
  • 2015-05-10 14:23
  • 702
    个人资料
    • 访问:102798次
    • 积分:3009
    • 等级:
    • 排名:第13799名
    • 原创:197篇
    • 转载:9篇
    • 译文:0篇
    • 评论:33条
    博客专栏
    最新评论