Description

在设计航线的时候,安全是一个很重要的问题。首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率。当飞机迫降到海上的时候,最近的陆地就是一个关键的因素。航线中最危险的地方就是距离最近的陆地最远的地方,我们称这种点为这条航线“孤地点”。孤地点到最近陆地的距离被称为“孤地距离”。作为航空公司的高级顾问,你接受的第一个任务就是尽量找出一条航线的孤地点,并计算这条航线的孤地距离。为了简化问题,我们认为地图是一个二维平面,陆地可以用多边形近似,飞行线路为一条折线。航线的起点和终点都在陆地上,但中间的转折点是可能在海上(如下图所示,方格标示出了孤地点)。 

Input

输入的第一行包括两个整数C和N(1≤C≤20,2≤N≤20),分别代表陆地的数目的航线的转折点的数目。接下来有N行,每行有两个整数x,y。(x,y)表示一个航线转折点的坐标,第一个转折点为航线的起点,最后一个转折点为航线的终点。接下来的输入将用来描述C块大陆。每块输入由一个正整数M开始(M≤30),M表示多边形的顶点个数,接下来的M行,每行会包含两个整数x,y,(x,y)表示多边形的一个顶点坐标,我们保证这些顶点以顺时针或逆时针给出了该多边形的闭包,不会出现某些边相交的情况。此外我们也保证输入数据中任何两块大陆不会相交。输入的所有坐标将保证在-10000到10000的范围之间。

Output

输出一个浮点数,表示航线的孤地距离,数据保留2位小数。

Sample Input

1 2
-9 -6
5 1
3
0 16
-16 -12
17 -6

Sample Output

0.00
 
吐槽:不得不说这种计算几何题TTM恶心了,对着数据(70个点用geogebra一一手打)调了3天。功夫不负有心人,还是切掉了。感谢我们学校的大神犇莫涛学长的算法,不然像我这种蒟蒻恐怕一辈子都写不出二分答案的正解。
 
为了表示膜拜,我将我的做法口述一遍吧(其实就是莫涛学长在论文上写的那种迭代),忽然间感觉自己和ydc比起来写得好丑。
  1. 先将所有不在多边形内部的线段加入队列中;
  2. 取出队首线段,找出与左端点最近的多边形上的点p1,右端点最近的多边形上的点p2。ans = max(ans,dis(p1,左端点),dis(p2,右端点));
  3. 在线段上二分出一个点p,使得dis(p,p1) == dis(p,p2);
  4. 若dis(p,p1) < ans,continue;否则,将线段二等分加入队列中;
  5. 重复2,3,4直到队列为空;

算法(减枝)就是这样。为什么这样是对的呢?我们证明一下:

我们现在要讨论的就是这个算法的正确性

现在我们有一条线段和对应的p1和p2,分别是左端点最近的点和右端点最近的点

有三种情况

然后我们发现线段上的点到自己最近点的距离不会超过max(dis(p1,p),dis(a,p1),(b,p2))(a,b分别为线段的左右端点)

所以我们的删除操作是对的,我们删除的都是不会更新答案的线段,就像ydc说的一样,这个就像是搜索剪枝

(注:上述证明转自:http://www.cnblogs.com/Randolph87/p/3642917.html)

最后再贴一份自己丑丑的代码:

 #include<algorithm>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std; #define rhl 10001
#define esp (1e-4)
#define maxn (30)
#define maxc (30)
#define maxm (40)
int tot,n,c,have[maxc]; double ans; inline double equal(double a,double b) { return fabs(a-b) < esp; } inline bool dd(double a,double b) { if (equal(a,b)) return true; return a >= b; } //>= inline bool xd(double a,double b) { if (equal(a,b)) return true; return a <= b; } //<= struct NODE
{
double x,y;
friend inline bool operator == (NODE a,NODE b) { return equal(a.x,b.x)&&equal(a.y,b.y); }
friend inline bool operator < (NODE a,NODE b)
{
if (a.x != b.x) return a.x < b.x;
else return a.y < b.y;
}
inline NODE ra()
{
int xx,yy;
do xx = rand()%rhl,yy = rand()%rhl;
while (equal(1.0*xx,x)||equal(1.0*yy,y));
return (NODE) {1.0*xx,1.0*yy};
}
inline void read() { scanf("%lf %lf",&x,&y); }
}pol[maxc][maxm],bac[maxc*maxm];
struct LINE
{
double a,b,c;
friend inline bool operator ==(LINE l1,LINE l2) { return equal(l1.a*l2.c,l2.a*l1.c); }
inline LINE vert(NODE p) { return (LINE) {b,-a,a*p.y-b*p.x}; }
inline bool on(NODE p) { return equal(,a*p.x+b*p.y+c); }
};
struct SEG{
NODE a,b;
inline NODE MID() { return (NODE) {(a.x+b.x)/,(a.y + b.y)/}; }
inline bool exist() { return !(a == b); }
inline LINE extend() { return (LINE) {a.y-b.y,b.x-a.x,b.y*(a.x-b.x)-b.x*(a.y-b.y)}; }
inline bool on(NODE p)
{
if (p == a) return true;
if (p == b) return true;
return (dd(p.x,min(a.x,b.x))&xd(p.x,max(a.x,b.x)))&&(dd(p.y,min(a.y,b.y))&xd(p.y,max(a.y,b.y)));
}
}temp[maxn];
queue <SEG> team; inline bool para(LINE l1,LINE l2) { return equal(l1.a * l2.b,l1.b * l2.a); } inline double qua(double a) { return a * a; } inline double dis(NODE a,NODE b) { return sqrt(qua(a.x - b.x)+qua(a.y - b.y)); } inline NODE cp(LINE l1,LINE l2)
{
double a1 = l1.a,b1 = l1.b,c1 = l1.c;
double a2 = l2.a,b2 = l2.b,c2 = l2.c;
double ry = (c2*a1-c1*a2)/(b1*a2-b2*a1),rx = (c1*b2-c2*b1)/(b1*a2-b2*a1);
return (NODE) {rx,ry};
} inline void cross(SEG s,int now)
{
LINE l = s.extend(),l1; SEG t; NODE p; NODE tt[maxm];
int cnt = ;
for (int i = ;i <= have[now];++i)
{
t = (SEG) {pol[now][i],pol[now][i-]};
l1 = t.extend();
if (para(l,l1))
{
if (l == l1)
{
if (s.on(t.a)) tt[++cnt] = t.a;
if (s.on(t.b)) tt[++cnt] = t.b;
}
continue;
}
p = cp(l,l1);
if (t.on(p) && s.on(p))
tt[++cnt] = p;
}
sort(tt+,tt+cnt+);
for (int i = ;i <= cnt;++i) bac[++tot] = tt[i];
} inline NODE find(NODE p)
{
NODE ret,q; LINE l1,l2; SEG s; double best = 1e9,len;
for (int i = ;i <= c;++i)
for (int j = ;j <= have[i];++j)
{
s = (SEG) {pol[i][j],pol[i][j-]};
l1 = s.extend();
l2 = l1.vert(p);
q = cp(l1,l2);
if (s.on(q))
{
len = dis(p,q);
if (best > len) ret = q,best = len;
}
else
{
if (dis(p,s.a) < dis(p,s.b)) q = s.a;
else q = s.b;
len = dis(p,q);
if (best > len) ret = q,best = len;
}
}
return ret;
} inline bool in(NODE p)
{
NODE q = p.ra(); SEG s = (SEG) {p,q},t; LINE l = s.extend(),l1; int cnt;
for (int i = ;i <= c;++i)
{
cnt = ;
for (int j = ;j <= have[i];++j)
{
t = (SEG) {pol[i][j],pol[i][j-]};
if ((t.extend()).on(p)&&t.on(p)) return false;
l1 = t.extend();
if (para(l,l1)) continue;
q = cp(l,l1);
if (dd(q.x,p.x)&&t.on(q)) ++cnt;
}
if (cnt & ) return true;
}
return false;
} inline void init()
{
for (int i = ;i < n;++i)
{
tot = ;
if (!(temp[i].a < temp[i].b)) swap(temp[i].a,temp[i].b);
for (int j = ;j <= c;++j)
cross(temp[i],j);
if (!in(temp[i].a)) bac[++tot] = temp[i].a;
if (!in(temp[i].b)) bac[++tot] = temp[i].b;
sort(bac+,bac+tot+);
for (int j = ;j < tot;j++)
if (!in((SEG){bac[j],bac[j+]}.MID()))
team.push((SEG){bac[j],bac[j+]});
}
} inline void work()
{
SEG now; NODE mid,p1,p2,l,r; double ret;
while (!team.empty())
{
now = team.front(); team.pop();
if (!now.exist()) continue;
p1 = find(now.a); p2 = find(now.b);
l = now.a,r = now.b;
while (!(l == r))
{
mid = ((SEG){l,r}).MID();
if (dis(p1,mid) > dis(p2,mid)) r = mid;
else l = mid;
}
ret = dis(r,p1);
ans = max(max(dis(now.a,p1),dis(now.b,p2)),ans);
if (ret-esp < ans) continue;
mid = now.MID();
team.push((SEG){now.a,mid}),team.push((SEG){mid,now.b});
}
} int main()
{
srand();
ans = ;
scanf("%d %d ",&c,&n);
NODE p1,p2; p1.read();
for (int i = ;i <= n;++i)
{
p2.read(); temp[i-] = (SEG) {p1,p2};
p1 = p2;
}
for (int i = ;i <= c;++i)
{
scanf("%d ",have+i);
for (int j = ;j <= have[i];++j) pol[i][j].read();
pol[i][] = pol[i][have[i]];
}
init();
work();
printf("%.2lf\n",ans);
fclose(stdin); fclose(stdout);
return ;
}

BZOJ 1020 安全的航线flight的更多相关文章

  1. 【BZOJ】【1020】【SHOI2008】安全的航线flight

    计算几何/二分/迭代/搜索+剪枝 写三个tag可能是因为从哪个方向来理解都可以吧…… 我完全不会计算几何所以抄了ydc的代码 题解:http://ydcydcy1.blog.163.com/blog/ ...

  2. BZOJ 1020 [SHOI2008]安全的航线flight

    1020: [SHOI2008]安全的航线flight Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 847  Solved: 286[Submit][ ...

  3. BZOJ 2200 道路与航线(图论)

    BZOJ 2200 道路与航线 题目大意 有两种路,一种没负数,一种没环,求单源最短路. solution 存在负边权Dij一定不能用嘛,显然不是 根据题意能看出来是tarjan,将双向边缩点,得到的 ...

  4. 1020: [SHOI2008]安全的航线flight - BZOJ

    Description在设计航线的时候,安全是一个很重要的问题.首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率.当飞机 ...

  5. 【BZOJ 1020】 [SHOI2008]安全的航线flight

    [题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1020 [题意] [题解] 二分+判断点是否在多边形区域内+计算点到直线的最短距离 对于 ...

  6. BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )

    首先我们要时光倒流, 倒着做, 变成加边操作维护关键边. 先随意搞出一颗树, 树上每条边都是关键边(因为是树, 去掉就不连通了)....然后加边(u, v)时, 路径(u, v)上的所有边都变成非关键 ...

  7. 【刷题】BZOJ 1969 [Ahoi2005]LANE 航线规划

    Description 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系--一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel ...

  8. BZOJ 2200 道路与航线

    好厉害呀这道题,有种豁然开朗的感觉.... 按拓扑顺序跑最短路. 然后注意细节,像WA的代码犯下的错是一笔带过没有丝毫考虑的...然而就是错了. 考试的时候一定要拍啊. #include<ios ...

  9. BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]

    题意: 一张图,删除边,求两点之间的割边数量.保证任意时刻图连通 任求一棵生成树,只有树边可能是割边 时间倒流,加入一条边,就是两点路径上的边都不可能是割边,区间覆盖... 然后本题需要把边哈希一下, ...

随机推荐

  1. IAAS云计算产品畅想-云主机产品内涵

    这里所涉及的主要还是狭义的云主机产品. 主要还是谈云主机产品中公有云产品与私有云产品相比赋予更多的含义: 产品广义理解:公有云主机的最大特点就是基础资源按需支付 从这一句话中可以体现出来两个含义: 产 ...

  2. Bluetooth 4.0之Android 解说

     Android平台包括了对蓝牙网络协议栈的支持,它同意一个蓝牙设备跟其它的蓝牙设备进行无线的数据交换.应用程序通过Android蓝牙API提供訪问蓝牙的功能. 这些API会把应用程序无线连接到其 ...

  3. HBase开发错误记录(一):java.net.UnknownHostException: unknown host: master

    windows下开发HBase应用程序.HBase部署在linux环境中, 在执行调试时可能会出现无法找到主机,类似异常信息例如以下: java.net.UnknownHostException: u ...

  4. SPOJ DQUERY 求区间内不同数的个数 主席树

    这题跟HDU3333差不多吧. 离线的做法很简单,不再说了 以前做过. 主席树的做法就比较暴力了.. 什么是主席树呢.. 其实是某种称号. 在该题中的体现是可持久化的线段树. 对于一个数 如果以前没出 ...

  5. java EE 学习

    http://blog.csdn.net/liushuijinger/article/category/1342030/1

  6. [转] Linux抓包工具tcpdump详解

    http://www.ha97.com/4550.html PS:tcpdump是一个用于截取网络分组,并输出分组内容的工具,简单说就是数据包抓包工具.tcpdump凭借强大的功能和灵活的截取策略,使 ...

  7. c#中跨线程调用windows窗体控件

    c#中跨线程调用windows窗体控件解决. 我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍.首先来 ...

  8. Navicat Premium 自动备份mysql和sqlserver

    mysql篇: 1.点击计划 2.点击新建处理作业 3.选择需要备份的数据库,上级可用任务 4.点击保存按钮,输入保存文件名 5.保存后点击设置计划任务 6.计划里新建保存时间,应用后输入系统密码即可 ...

  9. ASP.NET Boilerplate 工作单元

    从上往下说起,框架使用castle拦截器,拦截实现了IApplication.IRepository接口的所有方法,和使用了UnitOfWork 特性的方法,代码如下 internal class U ...

  10. Win7设置承载网络 分类: 网络 2014-10-30 09:08 105人阅读 评论(0) 收藏

    Win7设置承载网络 (1)最重要的第一步,要知道自己的网卡是否支持承载网络,如果不支持就悲剧地一票否决了,支持的话才能开始以后各步骤的设置. netsh wlan show drivers (2)设 ...