题解-POI2009 WSP-Island
Problem
题意概要:给定一个凸多边形坐标。点按顺时针编号 \(1\) 到 \(n\)。任意两点之间都有一条长度为欧氏距离的边相连。边相交处可以自由穿行。有 \(m\) 条边不能走,但是可以经过这条边与其他边的交点。问从点 \(1\) 到 \(n\) 的最短路(即给定完全图,删去\(m\)边,求最短路)
\(n\leq 10^5,m\leq 10^6\)
Solution
这个题还是挺巧妙的,只是画过图后就不难了
画两张图吧,就会发现只要贪心地往\(n\)号点走即可
发现只要贴着里面走就行(走红色路线),进一步发现每个点连出去的的几条线只有最靠内的线有用
所以当前边数可以减少到\(n\)条,然后就……做半平面交(\(\leftarrow\)本题最巧妙的一点)
Code
#include <bits/stdc++.h>
using namespace std;
inline void read(int&x){
char c11=getchar(),ob=0;x=0;
while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')ob=1,c11=getchar();
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;
}
const int N=201009,M=2001003;
const double eps=1e-8;
int n,m;bool pass=false;
struct Paris{
int x,y;
friend inline bool operator < (const Paris&A,const Paris&B)
{return A.x!=B.x?A.x<B.x:A.y>B.y;}
}pr[M];
struct pnt{
double x,y;
inline pnt(){}
inline pnt(const double&X,const double&Y):x(X),y(Y){}
inline void in(){scanf("%lf%lf",&x,&y);}
friend inline pnt operator + (const pnt&A,const pnt&B) {return pnt(A.x+B.x,A.y+B.y);}
friend inline pnt operator - (const pnt&A,const pnt&B) {return pnt(A.x-B.x,A.y-B.y);}
friend inline double operator * (const pnt&A,const pnt&B) {return A.x*B.y-A.y*B.x;}
inline pnt operator * (const double&B) const {return pnt(x*B,y*B);}
}p[N],dot[N];
inline double dis(pnt A,pnt B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
struct line{
pnt a,b;double slp;
inline void get_slp(){slp=atan2(b.y-a.y,b.x-a.x);}
friend inline bool operator < (const line&A,const line&B) {
if(fabs(A.slp-B.slp)>eps)
return A.slp<B.slp;
return (A.b-A.a)*(B.b-A.a)<0;
}
}l[N],q[N];
inline pnt crs(line A,line B){
double k1=(B.b-A.a)*(A.b-A.a);
double k2=(A.b-A.a)*(B.a-A.a);
return B.a+(B.b-B.a)*(k2/(k1+k2));
}
inline bool chk(line A,line B,line t){pnt p=crs(A,B);return (t.b-t.a)*(p-t.a)<0;}
void work(){
if(pass)return ;
for(int i=1;i<=n;++i)l[i].get_slp();
sort(l+1,l+n+1);
int tt=0;
for(int i=1;i<=n;++i)
if(fabs(l[i].slp-l[i-1].slp)>eps)
l[++tt]=l[i];
n=tt,tt=0;int L=1,R=0;
q[++R]=l[1],q[++R]=l[2];
for(int i=3;i<=n;++i){
while(L<R&&chk(q[R-1],q[R],l[i]))--R;
while(L<R&&chk(q[L],q[L+1],l[i]))++L;
q[++R]=l[i];
}
while(L<R&&chk(q[R-1],q[R],q[L]))--R;
while(L<R&&chk(q[L],q[L+1],q[R]))++L;
q[R+1]=q[L];
for(int i=L;i<=R;++i)
p[++tt]=crs(q[i],q[i+1]);
n=tt;
}
void input(){
read(n),read(m);
for(int i=1;i<=n;++i)dot[i].in();
for(int i=1;i<=m;++i)read(pr[i].x),read(pr[i].y);
for(int i=1;i<=n;++i)pr[++m].x=i,pr[m].y=i;
sort(pr+1,pr+m+1);
int tt;l[tt=1].a=dot[1],l[1].b=dot[n];
p[N-2].x=dot[1].x,p[N-2].y=dot[1].y;
p[N-1].x=dot[n].x,p[N-1].y=dot[n].y;
if(pr[1].x==1&&pr[1].y!=n){
printf("%.8lf\n",dis(p[N-1],p[N-2]));
pass=true;return ;
}
for(int id=1,i=1,j;id<=n;++id){
while(i<=m&&pr[i].x<id)++i;j=n;
while(pr[i].x==id&&pr[i].y==j)++i,--j;
if(j>id)l[++tt].a=dot[j],l[tt].b=dot[id];
}n=tt;
}
void print(){
if(pass)return ;
p[n+1]=p[1];
double res=0.0;
for(int i=1;i<=n;++i)
res+=dis(p[i],p[i+1]);
res-=dis(p[N-1],p[N-2]);
printf("%.8lf\n",res);
}
int main(){
input();
work();
print();
return 0;
}
题解-POI2009 WSP-Island的更多相关文章
- BZOJ 1137: [POI2009]Wsp 岛屿 半平面交
1137: [POI2009]Wsp 岛屿 Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 165 Solved: ...
- [题解] LuoguP4381 [IOI2008]Island
LuoguP4381 [IOI2008]Island Description 一句话题意:给一个基环树森林,求每棵基环树的直径长度的和(基环树的直径定义与树类似,即基环树上一条最长的简单路径),节点总 ...
- bzoj 1137 [POI2009]Wsp 岛屿
题目大意 Byteotia岛屿是一个凸多边形.城市全都在海岸上.按顺时针编号1到n.任意两个城市之间都有一条笔直的道路相连.道路相交处可以自由穿行.有一些道路被游击队控制了,不能走,但是可以经过这条道 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- 题解 CF540D 【Bad Luck Island】
既然没有大佬写题解那本蒟蒻就厚颜无耻地写(水)一(经)下(验)吧 题目要求算出个种人单独留下的存活率 因为n,m,p的范围极小, 那么就可以方便地设3位dp状态dp[i][j][k]表示剩余i个石头, ...
- 【题解】洛谷9月月赛加时赛 —— Never·island
有趣有趣~ヾ(✿゚▽゚)ノ真的很有意思的一道dp题!感觉可以提供很多非常有意思的思路~ 现场打的时候考虑了很久,但并没有做出来,主要还是卡在了两个地方:1.考虑到按照端点来进行dp,但没有办法将两个端 ...
- 【题解】Luogu P4381 [IOI2008]Island
原题传送门 题意:求基环树森林的直径(所有基环树直径之和) 首先,我们要对环上所有点的子树求出它们的直径和最大深度.然后,我们只用考虑在环上至少经过一条边的路径.那么,这种路径在环上一定有起始点和终点 ...
- 【题解】 bzoj1135: [POI2009]Lyz (线段树+霍尔定理)
题面戳我 Solution 二分图是显然的,用二分图匹配显然在这个范围会炸的很惨,我们考虑用霍尔定理. 我们任意选取穿\(l,r\)的号码鞋子的人,那么这些人可以穿的鞋子的范围是\(l,r+d\),这 ...
- HDU 4280 Island Transport(HLPP板子)题解
题意: 求最大流 思路: \(1e5\)条边,偷了一个超长的\(HLPP\)板子.复杂度\(n^2 \sqrt{m}\).但通常在随机情况下并没有isap快. 板子: template<clas ...
随机推荐
- 面向对象【day08】:类的起源与metaclass(二)
本节内容 1.概述 2.类的起源 3.__new__方法 4.__metaclass__方法 一.概述 前面我们学习了大篇幅的关于类,通过类创建对象,那我们想知道这个类到底是怎么产生的呢?它的一切来源 ...
- python脚本难点
本文主要记录在录制过程中,遇到一些需要特殊处理的脚本.如果有总结不好的地方,希望多多指点. 一.输入框listview选择: 如图: 类似这种情况,选择其中一项的脚本如下: m = driver. ...
- java.io.OutputStream & java.io.FileOutputStream
java.io.OutputStream & java.io.FileOutputStream 1.Java.io.OutputStream(字节输出流) 字节输出流,这是一个抽象类,是表示输 ...
- Kafka 简要使用说明
Kafka 简要使用说明 参考文章 Kafka背景及架构介绍http://www.infoq.com/cn/articles/kafka-analysis-part-1 Apache kafka 工作 ...
- ASP.NET Web API 2 使用 AuthorizationFilter(授权过滤器)实现 Basic 认证
Ø 前言 在 Web 项目中授权认证方式有很多种,本文主要讲述基于 Basic 的认证方式.这是一种比较简单.常见的认证方式,主要是将请求的用户名和密码进行加密后返回给调用方,比较适合采用用户名.密 ...
- error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
解决方案 1. http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 下载twisted对应版本的whl文件(我的Twisted‑17.5.0‑cp36 ...
- mysql load_file在数据库注入中使用
load_file函数只有满足两个条件就可以使用: 1.文件权限:chmod a+x pathtofile 2.文件大小: 必须小于max_allowed_packet 例子: select load ...
- TF, IDF和TF-IDF
在相似文本的推荐中,可以用TF-IDF来衡量文章之间的相似性. 一.TF(Term Frequency) TF的含义很明显,就是词出现的频率. 公式: 在算文本相似性的时候,可以采用这个思路,如果两篇 ...
- Linux修改MAC地址方法
Linux修改MAC地址方法 - Linux modifies MAC address method ifconfig wlan0 down ifconfig wlan0 hw ether MAC地址 ...
- 2.4 if-else
if-else 想一想:在使用if的时候,它只能做到满足条件时要做的事情.那万一需要在不满足条件的时候,做某些事,该怎么办呢? 答:使用 if-else <1>if-else的使用格式 i ...