【BZOJ 1038】【ZJOI 2008】瞭望塔

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

半平面交裸题,求完半平面后在折线段上的每个点竖直向上和半平面上的每个点竖直向下求距离,统计最小的值作为答案即可。

1A!!!斯巴达!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 303;

struct Point {
	double x, y;
	Point(double _x = 0, double _y = 0) : x(_x), y(_y) {}
} t[N], p[N];
struct Line {
	Point p, v; double ang;
	Line(Point _p = Point(0, 0), Point _v = Point(0, 0), double _ang = 0) : p(_p), v(_v), ang(_ang) {}
	bool operator < (const Line &x) const {
		return ang < x.ang;
	}
} l[N], q[N];

Point operator + (Point a, Point b) {return Point(a.x + b.x, a.y + b.y);}
Point operator - (Point a, Point b) {return Point(a.x - b.x, a.y - b.y);}
Point operator * (Point a, double x) {return Point(a.x * x, a.y * x);}
Point operator / (Point a, double x) {return Point(a.x / x, a.y / x);}

int dcmp(double x) {return fabs(x) < 1e-8 ? 0 : (x < 0 ? -1 : 1);}
double Dot(Point a, Point b) {return a.x * b.x + a.y * b.y;}
double Cross(Point a, Point b) {return a.x * b.y - a.y * b.x;}
double sqr(double x) {return x * x;}
double dis(Point a, Point b) {return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));}

bool onleft(Point a, Line b) {return dcmp(Cross(a - b.p, b.v)) < 0;}
Point intersection(Line a, Line b) {
	Point u; double t;
	u = a.p - b.p;
	t = Cross(b.v, u) / Cross(a.v, b.v);
	return a.p + (a.v * t);
}

int n, head = 1, tail = 2;
double ans;

void mkhalf() {
	q[1] = l[1]; q[2] = l[2];
	p[1] = intersection(q[1], q[2]);
	for(int i = 3; i < n; ++i) {
		while (head < tail && !onleft(p[tail - 1], l[i])) --tail;
		while (head < tail && !onleft(p[head], l[i])) ++head;
		q[++tail] = l[i];
		if (dcmp(Cross(q[tail].v, q[tail - 1].v) == 0)) {
			--tail;
			if (onleft(l[i].p, q[tail])) q[tail] = l[i];
		}
		if (head < tail) p[tail - 1] = intersection(q[tail - 1], q[tail]);
	}
//	while (head < tail + 1 && !onleft(p[tail - 1], q[head])) --tail;
}

double cal(int num) {
	Point j;
	double x = t[num].x, y = t[num].y;
	if (x <= p[head].x) {
		j = intersection(q[head], Line(t[num], Point(0, 1)));
		return j.y - y;
	}
	if (x >= p[tail - 1].x) {
		j = intersection(q[tail], Line(t[num], Point(0, 1)));
		return j.y - y;
	}
	int left = head, right = tail - 1, mid;
	while (left < right) {
		mid = (left + right + 1) >> 1;
		if (p[mid].x > x) right = mid - 1;
		else left = mid;
	}
	j = intersection(q[left + 1], Line(t[num], Point(0, 1)));
	return j.y - y;
}

double cal2(int num) {
	Point j;
	double x = p[num].x, y = p[num].y;
	int left = 1, right = n, mid;
	while (left < right) {
		mid = (left + right + 1) >> 1;
		if (t[mid].x > x) right = mid - 1;
		else left = mid;
	}
	j = intersection(Line(t[left], t[left + 1] - t[left]), Line(p[num], Point(0, -1)));
	return y - j.y;
}

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) scanf("%lf", &t[i].x);
	for(int i = 1; i <= n; ++i) scanf("%lf", &t[i].y);

	for(int i = 1; i < n; ++i) l[i] = Line(t[i], t[i + 1] - t[i]), l[i].ang = atan2(l[i].v.y, l[i].v.x);
	sort(l + 1, l + n);
	mkhalf();

	ans = cal(1);
	for(int i = 2; i <= n; ++i)
		ans = min(ans, cal(i));
	for(int i = head; i < tail; ++i)
		if (t[1].x <= p[i].x && p[i].x <= t[n].x)
			ans = min(ans, cal2(i));

//	for(int i = head; i < tail; ++i) printf("%.2lf %.2lf\n", p[i].x, p[i].y);

	printf("%.3lf\n", ans + 1e-8);
	return 0;
}

因为半平面不会围成一个"圈",所以我把最后"去除冗余"的部分注释掉了。最后输出答案加eps是听别人说的,不加会怎么样呢,我也不知道_(:з」∠)_

时间: 2024-10-07 00:21:27

【BZOJ 1038】【ZJOI 2008】瞭望塔的相关文章

BZOJ 1038 ZJOI 2008 瞭望塔 半平面交

题目大意:给出一个村庄的轮廓,在这个村庄里可以在随意的地方建一个瞭望塔.这个塔须要足够高,使得可以看得村庄的全貌. 求这个瞭望塔的最小高度. 思路:对于村庄中的每一条边,瞭望塔为了看见它.必需要在这个直线左側的半平面区域.这种话为了满足全部的边的需求,做一次半平面交,瞭望塔的最高点必须在全部边的半平面交的区域内. 例如以下图例子. 全部边的半平面交区域就是上面的图形.设上面半平面的函数关系是F(x).村长的函数关系是G(x),那么问题就转化成了求一个x,使得(F(x) - G(x))最小. 这个

【BZOJ 1038】 [ZJOI2008]瞭望塔

1038: [ZJOI2008]瞭望塔 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 973  Solved: 428 [Submit][Status] Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), -. (xn, yn)来描述H村的形状,这里x1 < x2 <

[BZOJ 1034] [ZJOI 2008] 泡泡堂BNB

1034: [ZJOI2008]泡泡堂BNB Time Limit: 10 SecMemory Limit: 162 MB Description 第XXXX届NOI期间,为了加强各省选手之间的交流,组委会决定组织一场省际电子竞技大赛,每一个省的代表队由n名选手组成,比赛的项目是老少咸宜的网络游戏泡泡堂.每一场比赛前,对阵双方的教练向组委会提交一份参赛选手的名单,决定了选手上场的顺序,一经确定,不得修改.比赛中,双方的一号选手,二号选手……,n号选手捉对厮杀,共进行n场比赛.每胜一场比赛得2分,

BZOJ 1040 ZJOI 2008 骑士 基环树林+树形DP

题目大意:有一些骑士,他们每个人都有一个权值.但是由于一些问题,每一个骑士都特别讨厌另一个骑士.所以不能把他们安排在一起.求这些骑士所组成的编队的最大权值和是多少. 思路:首先貌似是有向图的样子,但是一个人讨厌另一个人,他们两个就不能在一起,所以边可以看成是无向的. n个点,n条无向边,好像是一颗基环树.但其实这是一个基环树林,因为题中并没有说保证图一定联通. 然后就可以深搜了,处理出每一个联通块.其实每一个联通块就是一个基环树,在这个基环树上进行树形DP.求出最大值,然后累加到答案上.答案要开

【BZOJ】【1038】【ZJOI2008】瞭望塔

计算几何/半平面交 说是半平面交,实际上只是维护了个下凸壳而已……同1007水平可见直线 对于每条线段,能看到这条线段的点都在这条线段的“上方”,那么对所有n-1条线段求一个可视区域的交,就是求一个半平面交……(好扯) 一开始我想的是:直接找到这个下凸壳的最低点,它的y值就是答案辣-但是明显不对>_>这题让求的是塔的最低高度……不光要考虑塔顶,还要看塔底的啊! 那么我们怎么找呢?我们可以发现:随着x的变化,塔高(就是地面到凸壳的竖直距离,y坐标之差)是一个分段函数,分段点就是地面的折点以及凸壳

BZOJ 1038 瞭望塔

Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn.瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置.可见在不同的位置建造瞭望塔,所需要建造的高度是不同的.为了节省开支,dadzhi村长希望

BZOJ 1038 ZJOI2008 瞭望塔 模拟退火+二分答案

题目大意:给定一条折线,要求选择一个点建立高度为h的瞭望塔,要求瞭望塔塔顶可以看到折线上的每一个点,求h的最小值 正解:半平面交 不会! 于是我们选择模拟退火来寻找瞭望塔的横坐标 确定瞭望塔的高度的时候我们选择二分处理 对于二分的每一个值 我们把折线上的端点从左到右枚举 瞭望塔的塔尖到每个端点的连线必须从左到右逆时针顺序 否则就会被遮挡 如图,塔尖到点2的连线在到点1的连线的顺时针方向,故点1被遮挡,该高度不可行 写完交上去各种秒WA,最后发现我的INF又不够大...我沙茶,我蒟蒻,我这个不长记

【BZOJ 1036】【ZJOI 2008】树的统计

此题为树链剖分的裸题. 代码如下,使用常用的轻重链剖分. /************************************************************** Problem: 1036 User: Evensgn Language: C++ Result: Accepted Time:2468 ms Memory:5772 kb ****************************************************************/ #inc

bzoj千题计划126:bzoj1038: [ZJOI2008]瞭望塔

http://www.lydsy.com/JudgeOnline/problem.php?id=1038 本题可以使用三分法 将点按横坐标排好序后 对于任意相邻两个点连成的线段,瞭望塔的高度 是单峰函数,而且是下凸函数 感性理解单峰就是 瞭望塔建的靠左,为了能看到右边的,要高一点 瞭望塔建的靠右,为了能看到左边的,要高一点 所以 枚举所有线段,三分线段上建造瞭望塔的位置,所有线段上的瞭望塔高度取最小 #include<cmath> #include<cstdio> #include

1038: [ZJOI2008]瞭望塔

半平面交. 半平面指的就是一条直线的左面(也不知道对不对) 半平面交就是指很多半平面的公共部分. 这道题的解一定在各条直线的半平面交中. 而且瞭望塔只可能在各个点或者半平面交折线的拐点处. 求出半平面交,枚举即可. #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define eps 1e-7 using namespace std; const int maxn