BZOJ 1007 HNOI 2008 水平可见直线 计算几何+栈

题目大意:给出一些笛卡尔系中的一些直线,问从(0,+∞)向下看时能看到哪些直线。

思路:半平面交可做,但是显然用不上。类似于求凸包的思想,维护一个栈。先将所有直线按照k值排序,然后挨个压进去,遇到有前一个交点被挡住的话就先弹栈。

比较闹心的是去重。我的方法是压栈之前先去重,然后在处理。

CODE:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 50010
#define EPS 1e-5
using namespace std;

inline bool dcmp(double a,double b);

struct Point{
	double x,y;

	Point(double _ = 0,double __ = 0):x(_),y(__) {}
 	Point operator +(const Point &a)const {
		return Point(x + a.x,y + a.y);
	}
  	Point operator -(const Point &a)const {
		return Point(x - a.x,y - a.y);
	}
};
struct Line{
	double k,b;
	int _id;

	bool operator <(const Line &a)const {
		if(dcmp(k,a.k))	return b < a.b;
		return k < a.k;
	}
}line[MAX],_line[MAX];

int lines;
int top;
Line *stack[MAX];
Point intersection[MAX];

bool ans[MAX];

inline Point GetIntersection(const Line &l1,const Line &l2);
inline bool Under(const Line &l,const Point &p);

int main()
{
	cin >> lines;
	for(int i = 1;i <= lines; ++i) {
		scanf("%lf%lf",&line[i].k,&line[i].b);
		line[i]._id = i;
	}
	sort(line + 1,line + lines + 1);
	int cnt = 0;
	for(int i = 1;i <= lines; ++i) {
		if(dcmp(line[i].k,line[i + 1].k))	continue;
		_line[++cnt] = line[i];
	}
	stack[++top] = &_line[1];
	stack[++top] = &_line[2];
	intersection[top - 1] = GetIntersection(_line[1],_line[2]);
	for(int i = 3;i <= cnt; ++i) {
		if(i != cnt && _line[i].k == _line[i + 1].k)	continue;
		while(top > 1 && Under(_line[i],intersection[top - 1]))	--top;
		stack[++top] = &_line[i];
		intersection[top - 1] = GetIntersection(*stack[top],*stack[top - 1]);
	}
	for(int i = 1;i <= top; ++i)
		ans[stack[i]->_id] = true;
	for(int i = 1;i <= lines; ++i)
		if(ans[i])	printf("%d ",i);
	return 0;
}

inline bool dcmp(double a,double b)
{
	return fabs(a - b) < EPS;
}

inline Point GetIntersection(const Line &l1,const Line &l2)
{
	Point re;
	re.x = (l2.b - l1.b) / (l1.k - l2.k);
	re.y = re.x * l1.k + l1.b;
	return re;
}

inline bool Under(const Line &l,const Point &p)
{
	if(l.k * p.x + l.b > p.y || dcmp(l.k * p.x + l.b,p.y))	return true;
	return false;
}

时间: 2024-11-04 22:06:19

BZOJ 1007 HNOI 2008 水平可见直线 计算几何+栈的相关文章

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

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行输入A

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

BZOJ 1007 水平可见直线 题面 平面直角坐标系上有一些直线,请求出在纵坐标无限大处能看到哪些直线. 题解 将所有直线按照斜率排序(平行的直线只保留最高的直线),维护一个栈,当当前直线与栈顶直线的交点在栈顶两条直线的交点的左边,则弹出栈顶元素.可以画图证明这是正确的(因为我们要维护一个下凸的图形). #include <cmath> #include <cstdio> #include <cstring> #include <algorithm> us

BZOJ 1007: [HNOI2008]水平可见直线( 计算几何 )

按A从小到大排序然后用栈解决. -------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 50009; struct L { int A, B, id; inline void Read(int p) { scanf("%d%d"

bzoj1007: [HNOI2008]水平可见直线(单调栈)

1007: [HNOI2008]水平可见直线 题目:传送门 题解: 蒟蒻在bzoj上做的第一道计算几何 其实这道题并不难...(所以我A了) 仔细想想不难发现,其实我们只需要维护一个下凸的图形... 只有在这个图形上的直线才不会被覆盖,也就是可以被上帝直线看到的孩子 为什么呢...自己画个图模拟吧. 那么具体的做法我们就要采用单调栈啦! 把给出的直线按照斜率从小到大排序(如果斜率相同的话就按照b来排) 然后一个一个放入我们强大的单调栈中,在加入的同时我们当然还要进行维护: 如果栈顶的直线与新加直

[BZOJ1007][HNOI2008]水平可见直线 计算几何

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1007 可以发现题目求的就是一个下凸包,把直线按斜率排序,再来维护凸包就好了.可以发现下凸包上的拐点横坐标单增.同时注意处理斜率相同的直线的情况. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const double eps=1e-14;

[BZOJ 1008] [HNOI 2008] 越狱

1008: [HNOI2008]越狱 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5041  Solved: 2177[Submit][Status][Discuss] Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 Input 输入两个整数M,N.1<=M<=10^8,1<=N<=10

[BZOJ 1010][HNOI 2008] 玩具装箱toy

比较基础的斜率优化DP详见以下2篇博客 http://www.cnblogs.com/proverbs/archive/2012/10/06/2713109.html http://blog.163.com/myq_952/blog/static/863906320112711750378/ 主要总结斜率优化时的步骤 1.证明较优决策点对后续状态影响的持续性 2.求斜率方程:一般化为左边是J,K,右边是I的形式 3.规定队列的维护规则 4.看决策是否又单调性,没有的话有应该怎样维护 本题的代码

BZOJ 1009 HNOI 2008 GT考试 AC自动机+矩阵乘法

题目大意:给出一个不能出现的字符串,问长度为k的字符串有多少种. 思路:用给定串建立一个AC自动机(或者KMP随便了),然后跑矩阵乘法就行了. CODE: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int k,length,p; char s[MAX]; in

BZOJ 1004 HNOI 2008 Cards Burnside引理

题目大意:给出一个置换群,求有多少种本质不同的染色方案. 思路:Burnside引理:置换群的等价类数目=所有置换的不动点数目的平均值. 有了这个引理,我们只需要求出所有不动点的数目求一个平均值就可以的到等价类的数目了. 要使一种染色的方案在一种置换的意义下是不动点,需要让这个置换的每个循环节中的颜色都相同.先求出所有置换的循环,然后用一个背包就可以初解了.最后乘法逆元搞一下除法. CODE: #define _CRT_SECURE_NO_DEPRECATE #include <cstdio>