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

题意:给出n个x轴各不相同的二维整点,且升序,n<=300,坐标绝对值<=10^6,求这些点依次连接后折线的上面取一个点(x, y)使得:x0<=x<=xn,且这个点可以看得到所有线段的所有点。要求这些点到(垂直到)折线的y值之差最小。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <sstream>
using namespace std;
typedef long long ll;
#define pb push_back
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
inline int getint() { static int r, k; r=0,k=1; static char c; c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } const double eps=1e-6, oo=1e60;
const int N=1005;
int dcmp(double x) { return abs(x)<eps?0:(x<0?-1:1); }
struct iP { double x, y; iP(double _x=0, double _y=0) : x(_x), y(_y) {} };
typedef iP iV;
iV operator-(iP a, iP b) { return iV(a.x-b.x, a.y-b.y); }
iP operator+(iP a, iV b) { return iP(a.x+b.x, a.y+b.y); }
iV operator*(iV a, double x) { return iV(a.x*x, a.y*x); }
double cross(iV a, iV b) { return a.x*b.y-a.y*b.x; }
double angle(iV &a) { return atan2(a.y, a.x); } struct iL {
iP p; iV v; double ang;
iL() {}
iL(iP a, iP b) { set(a, b); }
void set(iP a, iP b) { p=a; v=b-a; ang=angle(v); }
bool operator< (const iL &b) const { return ang<b.ang; }
};
iP LLi(iL &a, iL &b) {
static iV u;
static double t;
u=a.p-b.p;
t=cross(b.v, u)/cross(a.v, b.v);
return a.p+a.v*t;
}
bool OnLeft(iP &p, iL &l) { return dcmp(cross(l.v, p-l.p))>0; }
bool half(iL *line, int ln, iP *s, int &cnt) {
static iL a[N], q[N];
static iP b[N];
memcpy(a, line, sizeof(iL)*(ln+1));
sort(a+1, a+1+ln);
int front=0, tail=0;
q[0]=a[1];
for1(i, 2, ln) {
while(front!=tail && !OnLeft(b[tail-1], a[i])) --tail;
while(front!=tail && !OnLeft(b[front], a[i])) ++front;
q[++tail]=a[i];
if(dcmp(cross(q[tail].v, q[tail-1].v))==0) {
--tail;
if(OnLeft(a[i].p, q[tail])) q[tail]=a[i];
}
if(front!=tail) b[tail-1]=LLi(q[tail-1], q[tail]);
}
while(front!=tail && !OnLeft(b[tail-1], q[front])) --tail;
if(tail-front<=1) return 0;
b[tail]=LLi(q[front], q[tail]);
cnt=0;
for1(i, front, tail) s[++cnt]=b[i];
return 1;
} iL line[N];
iP p[N], pp[N], a[N];
int n, ln, num;
void build() {
iP t1, t2;
for1(i, 1, n-1) line[i].set(a[i], a[i+1]);
ln=n-1;
++ln; line[ln].set(iP(oo, oo), iP(-oo, oo));
++ln; line[ln].set(iP(-oo, -oo), iP(oo, -oo));
++ln; line[ln].set(iP(-oo, oo), iP(-oo, -oo));
++ln; line[ln].set(iP(oo, -oo), iP(oo, oo));
}
double cal(iP &a, iP &b, double x) {
double k=(b.y-a.y)/(b.x-a.x), B=a.y-k*a.x;
return k*x+B;
}
int main() {
read(n);
for1(i, 1, n) a[i].x=getint();
for1(i, 1, n) a[i].y=getint();
build();
half(line, ln, pp, num);
double ans=oo;
double mnx=oo, mny=oo; int pos=1;
for1(i, 1, num) if(dcmp(mnx-pp[i].x)>0 || (dcmp(mnx-pp[i].x)==0 && dcmp(mny-pp[i].y)>0)) { mnx=pp[i].x; mny=pp[i].y; pos=i; }
for1(i, 1, num) p[i]=pp[pos], pos=pos%num+1;
int now=2;
for1(i, 1, n) {
while(now<num && dcmp(p[now].x-a[i].x)<0) ++now;
if(dcmp(a[i].x-p[now-1].x)>=0 && dcmp(p[now].x-a[i].x)>=0)
ans=min(ans, cal(p[now], p[now-1], a[i].x)-a[i].y);
}
now=2;
for1(i, 1, num) {
while(now<n && dcmp(a[now].x-p[i].x)<0) ++now;
if(dcmp(p[i].x-a[now-1].x)>=0 && dcmp(a[now].x-p[i].x)>=0)
ans=min(ans, p[i].y-cal(a[now], a[now-1], p[i].x));
}
printf("%.3f\n", ans+eps);
return 0;
}

  


计算几何题一定要先想好再码!!!而且一定要注意精度问题!!!!因为答案0.00可能变成-0.00.....(一切都是精度的错..),因此我们在输出答案时别忘了加上eps........

本题首先可以发现,可以取的点一定在每条有向线段(就是p[i]到p[i+1])所在直线的左边,所以答案点在这些直线的交中.

即半平面交.....

然后我sb了.............我竟然以为直接二分距离,然后在加一条y=maxh+h的直线然后判断是否存在半平面...........................................显然这样没有考虑到是垂直到达折线段.........................

考虑到,这个半平面交其实是个凸的,而且,他们一定在所有线段的上方...............而每条线段和凸包上的线段都是直的,即线上的点有单调性......因此,最短距离一定在折线端点到另一个图的线段上...

所以分类枚举凸包的点和原来的点判断到另一个凸线的距离即可.......................

求半平面交的算法很简单...........先极角排序,然后用一个双端队列维护,且判断当前直线是否在队列中的直线的交点的左边,如果是则出列.............

然后之前求直线交点喜闻乐见写错一个地方调了1h.............

反正写这题用了3h左右吧......太弱了.............

【BZOJ】1038: [ZJOI2008]瞭望塔的更多相关文章

  1. bzoj 1038 [ZJOI2008]瞭望塔(半平面交)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1038 [题意] 找一个最低塔高使可以看到村庄的每一个角落. [思路] 半平面交 能够看 ...

  2. BZOJ 1038 ZJOI2008 瞭望塔 半平面交

    题目大意及模拟退火题解:见 http://blog.csdn.net/popoqqq/article/details/39340759 这次用半平面交写了一遍--求出半平面交之后.枚举原图和半平面交的 ...

  3. 【BZOJ 1038】 1038: [ZJOI2008]瞭望塔

    1038: [ZJOI2008]瞭望塔 Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 ...

  4. 1038: [ZJOI2008]瞭望塔 - BZOJ

    Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, ...

  5. 1038: [ZJOI2008]瞭望塔

    半平面交. 半平面指的就是一条直线的左面(也不知道对不对) 半平面交就是指很多半平面的公共部分. 这道题的解一定在各条直线的半平面交中. 而且瞭望塔只可能在各个点或者半平面交折线的拐点处. 求出半平面 ...

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=1038 本题可以使用三分法 将点按横坐标排好序后 对于任意相邻两个点连成的线段,瞭望塔的高度 是单峰函 ...

  7. [BZOJ1038][ZJOI2008]瞭望塔(半平面交)

    1038: [ZJOI2008]瞭望塔 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2999  Solved: 1227[Submit][Statu ...

  8. 【BZOJ1038】[ZJOI2008]瞭望塔 半平面交

    [BZOJ1038][ZJOI2008]瞭望塔 Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如 ...

  9. 【BZOJ 1038】[ZJOI2008]瞭望塔

    [题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1038 [题意] [题解] 可以看到所有村子的瞭望塔所在的位置只会是在相邻两个村子所代表 ...

随机推荐

  1. [ruby on rails] 跟我学之(3)基于rails console的查增删改操作

    本章节展开对model的介绍:包括查增删改操作.紧接着上面一节<[ruby on rails] 跟我学之HelloWorld> 创建模型 使用命令创建模型 创建表post,默认自带两栏位 ...

  2. 记录:js删除数组中某一项或几项的几种方法

    1:js中的splice方法 splice(index,len,[item])    注释:该方法会改变原始数组. splice有3个参数,它也可以用来替换/删除/添加数组内某一个或者几个值 inde ...

  3. Linux下crontab命令的用法

    cron来源于希腊单词chronos(意为“时间”),是linux系统下一个自动执行指定任务的程序.例如,你想在每晚睡觉期间创建某些文件或文件夹的备份,就可以用cron来自动执行. 服务的启动和停止 ...

  4. android.mk文件里的通配符

    比方你有如下目录,要编译Classes目录和Code目录下所有cpp src |-android.mk |-Classes |-A.cpp |-B.cpp |-....cpp |-Code |-E.c ...

  5. iOS 关于UITableView的dequeueReusableCellWithIdentifier

    今天看代码的时候,突然想到了以前的一个问题. 刚学ios那会儿,常会写出以下代码 - (UITableViewCell *)tableView:(UITableView *)tableView cel ...

  6. 解决 jersey javax.ws.rs.core.UriBuilder.fromUri(UriBuilder.java:119)

    检查是否Jar冲突 保留一个jersey-server-*.jar

  7. AU版有锁机的福利,704越狱彻底解决+86问题,完美IM/FT,重启不掉APN设置

    http://bbs.25pp.com/thread-172881-1-1.html 串号99的是au版 串号013的是sb版 44050   AU为 找到咱们SB版的文件,为44020 http:/ ...

  8. Ubuntu中root用户和user用户的相互切换

    转:Ubuntu是最近很流行的一款Linux系统,因为Ubuntu默认是不启动root用户,现在介绍如何进入root的方法. (1)从user用户切换到root用户 不管是用图形模式登录Ubuntu, ...

  9. Maven使用笔记(一)Maven安装及常用命令

    1.Windows下安装Maven 首先去下载Maven安装包,http://maven.apache.org/download.cgi,目前最新版本是 Maven 3.2.3 . 解压到本地,可以看 ...

  10. Linux下如何设置和查看环境变量

    Linux的变量种类 按变量的生存周期来划分,Linux变量可分为两类: 1 永久的:需要修改配置文件,变量永久生效. 2 临时的:使用export命令声明即可,变量在关闭shell时失效. 按作用范 ...