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

二分/迭代/搜索+剪枝



  写三个tag可能是因为从哪个方向来理解都可以吧……

  我完全不会计算几何所以抄了ydc的代码

  题解:http://ydcydcy1.blog.163.com/blog/static/21608904020131492229367/

  那篇莫涛的论文:http://pan.baidu.com/s/1bn6IxJp

大概流程如下:

  1.初始化孤地点可能位于的线段集合为整条航线。

  2.对于长$L$的某条线段,左端点与陆地的最近点为$P_1$,右端点与陆地的最近点为$P_2$,那么该线段上的孤地距离将受$P_1$与$P_2$影响。具体来说,利用二分求出改线段上的点$P$使得$$ Minimize \ y = max\{Dis\{P,P_1\},Dis\{P,P_2\}\}$$若$y$小于已有的最优答案,那么可以删除该线段。

  3.取所有线段的中点更新答案。

  4.将所有线段从重点分成左右两条线段。

  5.不断进行2,3,4直到线段的集合为空。

  整个过程中最复杂的计算集合操作是第3步中求点与线段的距离,并且不会出现因精度导致的判断问题,而运行速度也不错,极限数举只需0.05秒,是一个相当优秀的算法。

(才怪啊!那判断点是否在陆地上不是也得写射线法和点在线段上?判断是否在多边形内部……)

  1 /**************************************************************
  2     Problem: 1020
  3     User: Tunix
  4     Language: C++
  5     Result: Accepted
  6     Time:92 ms
  7     Memory:32544 kb
  8 ****************************************************************/
  9
 10 //BZOJ 1020
 11 #include<cmath>
 12 #include<vector>
 13 #include<cstdio>
 14 #include<cstring>
 15 #include<cstdlib>
 16 #include<iostream>
 17 #include<algorithm>
 18 #define rep(i,n) for(int i=0;i<n;++i)
 19 #define F(i,j,n) for(int i=j;i<=n;++i)
 20 #define D(i,j,n) for(int i=j;i>=n;--i)
 21 #define pb push_back
 22 using namespace std;
 23 inline int getint(){
 24     int v=0,sign=1; char ch=getchar();
 25     while(ch<‘0‘||ch>‘9‘){ if (ch==‘-‘) sign=-1; ch=getchar();}
 26     while(ch>=‘0‘&&ch<=‘9‘){ v=v*10+ch-‘0‘; ch=getchar();}
 27     return v*sign;
 28 }
 29 const int N=30,M=40,MAXQ=1e6,INF=~0u>>2;
 30 const double eps=1e-16;
 31 typedef long long LL;
 32 typedef double db;
 33 /******************tamplate*********************/
 34 int dcmp(db p){if(fabs(p)<eps) return 0;else return p>eps?1:-1;}
 35 int n,m;
 36 db ans;
 37 struct Point{
 38     db x,y;
 39     Point(){}
 40     Point(db x,db y):x(x),y(y){}
 41     void Read(){scanf("%lf %lf",&x,&y);}
 42 }temp[N];
 43 Point operator + (const Point &a,const Point &b){return Point(a.x+b.x,a.y+b.y);}
 44 Point operator - (const Point &a,const Point &b){return Point(a.x-b.x,a.y-b.y);}
 45 Point operator * (const Point &a,db p){return Point(a.x*p,a.y*p);}
 46 Point operator / (const Point &a,db p){return Point(a.x/p,a.y/p);}
 47 bool operator == (const Point &a,const Point &b){return !dcmp(a.x-b.x)&&!dcmp(a.y-b.y);}
 48 typedef Point Vector;
 49 double Dot(const Vector &a,const Vector &b){return a.x*b.x+a.y*b.y;}
 50 double Len(const Vector &a){return sqrt(Dot(a,a));}
 51 double Cross(const Vector &a,const Vector &b){return a.x*b.y-a.y*b.x;}
 52 Vector Normal(const Vector &a){return Vector(-a.y,a.x);}
 53 bool On(const Point &a,const Point &b,const Point &c){
 54     return !dcmp(Cross(b-a,c-a))&&
 55         dcmp((a.x-b.x)*(a.x-c.x))<=0&&dcmp((a.y-b.y)*(a.y-c.y))<=0;
 56 }
 57 bool inter(const Point &a,const Point &b,const Point &c,const Point &d){
 58     return dcmp(Cross(c-a,b-a)*Cross(d-a,b-a))<=0 && dcmp(Cross(a-c,d-c)*Cross(b-c,d-c))<=0;
 59 }
 60 Point getinter(const Point &a,const Vector &b,const Point &c,const Vector &d){
 61     Vector u=a-c;
 62     double t=Cross(d,u)/Cross(b,d);
 63     return a+b*t;
 64 }
 65 struct Seg{
 66     Point a,b;
 67     Seg(){}
 68     Seg(const Point &a,const Point &b):a(a),b(b){}
 69 }queue[MAXQ];
 70 struct Polygon{
 71     Point p[M];
 72     int tot;
 73     bool In(Point &point){
 74         int total=0;
 75         F(i,1,tot)
 76             if (On(point,p[i],p[i%tot+1]))
 77                 return true;
 78         Point Ray=Point(-10001,point.y+0.1);
 79         point.y+=0.1;
 80         F(i,1,tot)
 81             total=total+inter(Ray,point,p[i],p[i%tot+1]);
 82         point.y-=0.1;
 83         return total&1;
 84     }
 85 }island[N];
 86 struct near{
 87     Point P;
 88     double dis;
 89     near(){}
 90     near(const Point &a,double b):P(a),dis(b){}
 91 };
 92 near DISPS(const Point &a,const Point &b,const Point &c){
 93     if (b==c) return near(b,Len(b-a));
 94     Vector v1=c-b,v2=a-b,v3=a-c;
 95     if (dcmp(Dot(v1,v2))<=0) return near(b,Len(v2));
 96     if (dcmp(Dot(v1,v3))>=0) return near(c,Len(v3));
 97     Vector v=Normal(b-c);
 98     Point ans=getinter(a,v,b,v1);
 99     return near(ans,Len(a-ans));
100 }
101 bool check(Point &P){
102     F(i,1,n)
103         if (island[i].In(P))
104             return true;
105     return false;
106 }
107 near Find(Point &P){
108     if (check(P)) return near(P,0);
109     near ans1;
110     ans1.dis=1<<30;
111     F(i,1,n)
112         F(j,1,island[i].tot){
113             near get=DISPS(P,island[i].p[j],island[i].p[j%island[i].tot+1]);
114             if (dcmp(ans1.dis-get.dis)>=0) ans1=get;
115         }
116     ans=max(ans,ans1.dis);
117     return ans1;
118 }
119 void read(){
120     n=getint(); m=getint();
121     F(i,1,m) temp[i].Read();
122     F(i,1,n){
123         island[i].tot=getint();
124         F(j,1,island[i].tot)
125             island[i].p[j].Read();
126     }
127 }
128 void search(){
129     int front=0,rear=0;
130     F(i,1,m-1)
131         queue[++rear]=Seg(temp[i],temp[i+1]),Find(temp[i]);
132     Find(temp[m]);
133     Seg head;
134     while(front!=rear){
135         head=queue[front=front%MAXQ+1];
136         Point p1=Find(head.a).P,p2=Find(head.b).P,
137               l=head.a,r=head.b,mid=(l+r)/2;
138         while(Len(r-l)>1e-4){
139             Point mid=(r+l)/2;
140             if (Len(mid-p1)<Len(mid-p2)) l=mid;
141             else r=mid;
142         }
143         double nowans=max(Len(l-p1),Len(l-p2));
144         Find(l);
145         if (ans+0.005<nowans)
146             queue[rear=rear%MAXQ+1]=Seg(head.a,mid),
147             queue[rear=rear%MAXQ+1]=Seg(mid,head.b);
148     }
149 }
150 int main(){
151 #ifndef ONLINE_JUDGE
152     freopen("1020.in","r",stdin);
153     freopen("1020.out","w",stdout);
154 #endif
155     read();
156     search();
157     printf("%.2lf\n",ans);
158     return 0;
159 }

1020: [SHOI2008]安全的航线flight

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 786  Solved: 254
[Submit][Status][Discuss]

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

HINT

Source

NWERC 2007

[Submit][Status][Discuss]

时间: 2024-11-16 20:15:09

【BZOJ】【1020】【SHOI2008】安全的航线flight的相关文章

BZOJ 1020 [SHOI2008]安全的航线flight

1020: [SHOI2008]安全的航线flight Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 847  Solved: 286[Submit][Status][Discuss] Description 在设计航线的时候,安全是一个很重要的问题.首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率.当飞机迫降到海上的时候,最近的陆地就是一个关键的因素.航线中最危险的地

bzoj 1020[SHOI2008]安全的航线flight - 迭代+二分

1020: [SHOI2008]安全的航线flight Time Limit: 5 Sec  Memory Limit: 162 MB Description 在设计航线的时候,安全是一个很重要的问题.首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率.当飞机迫降到海上的时候,最近的陆地就是一个关键的因素.航线中最危险的地方就是距离最近的陆地最远的地方,我们称这种点为这条航线"孤地点".孤地点到最近陆地的距离

bzoj 1022: [SHOI2008]小约翰的游戏John anti_nim游戏

1022: [SHOI2008]小约翰的游戏John Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1189  Solved: 734[Submit][Status] Description 小 约翰经常和他的哥哥玩一个非常有趣的游戏:桌子上有n堆石子,小约翰和他的哥哥轮流取石子,每个人取的时候,可以随意选择一堆石子,在这堆石子中取走任意 多的石子,但不能一粒石子也不取,我们规定取到最后一粒石子的人算输.小约翰相当固执,他坚持认为先取的人有很大的优

BZOJ 1020 安全的航线flight

Description 在设计航线的时候,安全是一个很重要的问题.首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率.当飞机迫降到海上的时候,最近的陆地就是一个关键的因素.航线中最危险的地方就是距离最近的陆地最远的地方,我们称这种点为这条航线“孤地点”.孤地点到最近陆地的距离被称为“孤地距离”.作为航空公司的高级顾问,你接受的第一个任务就是尽量找出一条航线的孤地点,并计算这条航线的孤地距离.为了简化问题,我们认为地图是

bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan索环&amp;&amp;环上单调队列

1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1141  Solved: 435[Submit][Status] Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路. 举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路

BZOJ 1021: [SHOI2008]Debt 循环的债务( dp )

dp(i, j, k)表示考虑了前i种钱币(从小到大), Alice的钱数为j, Bob的钱数为k, 最小次数. 脑补一下可以发现, 只有A->B.C, B->A.C, C->A.B, A.B->C, A.C->B, B.C->A 6情况, 枚举然后dp一下就OK了. dp用刷表的话,有个强有力的剪枝是之后的硬币无论如何组合都无法满足时不去更新. --------------------------------------------------------------

[BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】

题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经典模型. 我们线段树的一个节点表示一个区间的联通性,有 6 个 bool 值,表示这个区间的 4 个角上的点之间的联通性. 然后用两个子区间的联通性和两个子区间之间的连边情况合并出整个区间的联通性. 修改某条边时,先在边的数组中修改,然后从这条边所在的点的线段树叶子开始向上 Update . 询问两

BZOJ 1018: [SHOI2008]堵塞的交通traffic [线段树 区间信息]

1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 3064  Solved: 1027[Submit][Status][Discuss] Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 小人国的交通

数据结构(线段树):BZOJ 1018: [SHOI2008]堵塞的交通traffic

1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 2638  Solved: 864 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 小人国的交通状况非常槽糕.有的时候由于交通堵塞,两座城市之间的道