POJ 3549 GSM phone(圆+扫描线+最短路)
题目意思是求起点s到终点s的最短路,但是只能在圆的内部和边上走。一种可以想到的方法就是求出所有的交点,然后两两连边并验证合法性,但是这样的交点数规模有n2。
我们可以观察发现,我们在圆求并构成的图形中,在其内部的点是不可能成为最短路上的点,只可能是沿着边上的点擦着经过,所以我们需要把在圆内部的所有点都给扣掉,同样可以证明这样的点的规模只有n个,接下来只需要暴力连边,但是连边的时候需要验证这样的点对是否沿着直线可达。我是直接将这条线段暴力和所有圆求交点,左侧端点计为1,右侧端点计为-1,然后用类似于扫描线的做法sort一遍,最后判断线段的两端是否被这个区间包含即可。
最后跑一边dijk就求出答案。
这个方法感觉不是很好.... 还有比我快20倍的orz...
如果扣的是灰色点那么规模有n2
如果是外侧点只有n个,绿色点即为可用点,红色和橙色为两条路,则最短路必然擦过外侧点或者起点终点直接相连
// ——By DD_BOND //#include<bits/stdc++.h>
//#include<unordered_map>
//#include<unordered_set>
#include<functional>
#include<algorithm>
#include<iostream>
//#include<ext/rope>
#include<iomanip>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<cstddef>
#include<cstdio>
#include<memory>
#include<vector>
#include<cctype>
#include<string>
#include<cmath>
#include<queue>
#include<deque>
#include<ctime>
#include<stack>
#include<map>
#include<set>
#include<cassert> #define fi first
#define se second
#define pb push_back
#define MP make_pair #pragma GCC optimize(3)
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") using namespace std; typedef long double db;
typedef long long ll;
typedef pair<db,db> Pd;
typedef pair<int,int> P;
typedef pair<ll,ll> Pll; const db eps=1e-;
const int MAXN=1e5+;
const db pi=acos(-1.0);
const ll INF=0x3f3f3f3f3f3f3f3f; inline int dcmp(db x){
if(fabs(x)<eps) return ;
return (x>? : -);
} inline db Sqrt(db x){
return x>? sqrt(x): ;
} inline db sqr(db x){ return x*x; } struct Point{
db x,y;
Point(){ x=,y=; }
Point(db _x,db _y):x(_x),y(_y){}
void input(){
double _x,_y;
scanf("%lf%lf",&_x,&_y);
x=_x,y=_y;
}
void output(){ printf("%.2f %.2f\n",(double)x,(double)y); }
friend istream &operator >>(istream &os,Point &b){
os>>b.x>>b.y;
return os;
}
friend ostream &operator <<(ostream &os,Point &b){
os<<b.x<<' '<<b.y;
return os;
}
bool operator ==(const Point &b)const{
return (dcmp(x-b.x)==&&dcmp(y-b.y)==);
}
bool operator !=(const Point &b)const{
return !((dcmp(x-b.x)==&&dcmp(y-b.y)==));
}
bool operator <(const Point &b)const{
return (dcmp(x-b.x)==? dcmp(y-b.y)< : x<b.x);
}
db operator ^(const Point &b)const{ //叉积
return x*b.y-y*b.x;
}
db operator *(const Point &b)const{ //点积
return x*b.x+y*b.y;
}
Point operator +(const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator -(const Point &b)const{
return Point(x-b.x,y-b.y);
}
Point operator *(db a){
return Point(x*a,y*a);
}
Point operator /(db a){
return Point(x/a,y/a);
}
db len2(){ //长度平方
return sqr(x)+sqr(y);
}
db len(){ //长度
return Sqrt(len2());
}
Point change_len(db r){ //转化为长度为r的向量
db l=len();
if(dcmp(l)==) return *this; //零向量
return Point(x*r/l,y*r/l);
}
Point rotate_left(){ //逆时针旋转90度
return Point(-y,x);
}
Point rotate_right(){ //顺时针旋转90度
return Point(y,-x);
}
}; inline db cross(Point a,Point b){ //叉积
return a.x*b.y-a.y*b.x;
} inline db dot(Point a,Point b){ //点积
return a.x*b.x+a.y*b.y;
} inline db dis(Point a,Point b){ //两点的距离
Point p=b-a; return p.len();
} struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
void input(){
s.input();
e.input();
}
db length(){ //线段长度
return dis(s,e);
}
}; inline db point_to_line(Point p,Line a){ //点到直线距离
return fabs(cross(p-a.s,a.e-a.s)/a.length());
} inline Point projection(Point p,Line a){ //点在直线上的投影
return a.s+(((a.e-a.s)*dot(a.e-a.s,p-a.s))/(a.e-a.s).len2());
} struct Circle{
Point p;
db r;
Circle(){}
void input(){
p.input();
double _r;
scanf("%lf",&_r);
r=_r;
}
}; inline int relation(Point p,Circle a){ //点和圆的位置关系 0:圆外 1:圆上 2:圆内
db d=dis(p,a.p);
if(dcmp(d-a.r)==) return ;
return (dcmp(d-a.r)<? : );
} inline int relation(Line a,Circle b){ //直线和圆的位置关系 0:相离 1:相切 2:相交
db p=point_to_line(b.p,a);
if(dcmp(p-b.r)==) return ;
return (dcmp(p-b.r)<? : );
} inline int relation(Circle a,Circle v){ //圆和圆的位置关系 1:内含 2:内切 3:相交 4:外切 5:相离
db d=dis(a.p,v.p);
if(dcmp(d-a.r-v.r)>) return ;
if(dcmp(d-a.r-v.r)==) return ;
db l=fabs(a.r-v.r);
if(dcmp(d-l)>) return ;
if(dcmp(d-l)==) return ;
return ;
} inline int circle_intersection(Circle a,Circle v,Point &p1,Point &p2){ //两个圆的交点
int rel=relation(a,v); //返回交点个数,保存在引用中
if(rel==||rel==) return ;
db d=dis(a.p,v.p);
db l=(d*d+a.r*a.r-v.r*v.r)/(*d);
db h=Sqrt(a.r*a.r-l*l);
Point tmp=a.p+(v.p-a.p).change_len(l);
p1=tmp+((v.p-a.p).rotate_left().change_len(h));
p2=tmp+((v.p-a.p).rotate_right().change_len(h));
if(rel==||rel==) return ;
return ;
} inline int line_circle_intersection(Line v,Circle u,Point &p1,Point &p2){ //直线和圆的交点
if(!relation(v,u)) return ; //返回交点个数,保存在引用中
Point a=projection(u.p,v);
db d=point_to_line(u.p,v);
d=Sqrt(u.r*u.r-d*d);
if(dcmp(d)==){
p1=a,p2=a;
return ;
}
p1=a+(v.e-v.s).change_len(d);
p2=a-(v.e-v.s).change_len(d);
return ;
} typedef pair<db,int>pdi;
typedef pair<Point,int> pd; vector<pdi>edge[MAXN]; db d[MAXN];
pd st[MAXN];
bool mark[MAXN];
Circle circle[MAXN];
Point s,t,it1,it2,inter[MAXN],point[MAXN]; priority_queue<pdi,vector<pdi>,greater<pdi> >q; bool cmp(pd a,pd b){
if(a==b) return a.se>b.se;
return a<b;
} int main(void){
s.input(); t.input();
int n,m=,cnt=; scanf("%d",&n);
for(int i=;i<=n;i++) circle[i].input();
for(int i=;i<=n;i++)
for(int j=i+;j<=n;j++){
int p=relation(circle[i],circle[j]);
if(p==||p==||p==){
circle_intersection(circle[i],circle[j],it1,it2);
point[m++]=it1,point[m++]=it2;
}
}
sort(point+,point+m);
m=unique(point+,point+m)-point;
for(int i=;i<m;i++)
for(int j=;j<=n;j++)
if(relation(point[i],circle[j])==){
mark[i]=;
break;
}
for(int i=;i<m;i++)
if(mark[i]==)
point[cnt++]=point[i];
m=cnt; point[]=s,point[m]=t;
for(int i=;i<=m;i++)
for(int j=i+;j<=m;j++){
int p=;
Line l(point[i],point[j]);
Point p1=point[i],p2=point[j];
if(p2<p1) swap(p1,p2);
for(int k=;k<=n;k++){
Circle c=circle[k];
if(relation(l,c)){
line_circle_intersection(l,c,it1,it2);
if(it2<it1) swap(it1,it2);
st[p++]=pd(it1,);
st[p++]=pd(it2,-);
}
}
int found=;
sort(st,st+p,cmp);
for(int k=,sum=,start=;k<p;k++){
sum+=st[k].se;
if(sum==){
if(!(p1<st[start].fi)&&!(st[k].fi<p2)) found=;
start=k+;
}
}
if(found){
edge[i].pb(pdi(l.length(),j));
edge[j].pb(pdi(l.length(),i));
}
}
for(int i=;i<=m;i++) d[i]=1e20;
q.push(pdi(,));
while(!q.empty()){
pdi p=q.top(); q.pop();
if(dcmp(d[p.se]-p.fi)<) continue;
for(int i=;i<edge[p.se].size();i++){
int v=edge[p.se][i].se;
db val=edge[p.se][i].fi;
if(dcmp(d[p.se]+val-d[v])<){
d[v]=d[p.se]+val;
q.push(pdi(d[v],v));
}
}
}
printf("%.5f\n",(double)d[m]);
return ;
}
POJ 3549 GSM phone(圆+扫描线+最短路)的更多相关文章
- POJ 2932 圆扫描线
求n个圆中没有被包含的圆.模仿扫描线从左往右扫,到左边界此时如有3个交点,则有3种情况,以此判定该圆是否被离它最近的圆包含,而交点和最近的圆可以用以y高度排序的Set来维护.因此每次到左边界插入该圆, ...
- HDU 3511 圆扫描线
找最深的圆,输出层数 类似POJ 2932的做法 圆扫描线即可.这里要记录各个圆的层数,所以多加一个维护编号的就行了. /** @Date : 2017-10-18 18:16:52 * @FileN ...
- HDU 4063 线段与圆相交+最短路
Aircraft Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...
- poj 3613 经过k条边最短路 floyd+矩阵快速幂
http://poj.org/problem?id=3613 s->t上经过k条边的最短路 先把1000范围的点离散化到200中,然后使用最短路可以使用floyd,由于求的是经过k条路的最短路, ...
- 【POJ】2449 Remmarguts' Date(k短路)
http://poj.org/problem?id=2449 不会.. 百度学习.. 恩. k短路不难理解的. 结合了a_star的思想.每动一次进行一次估价,然后找最小的(此时的最短路)然后累计到k ...
- POJ 3255 Roadblocks(A*求次短路)
Roadblocks Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 12167 Accepted: 4300 Descr ...
- poj 2449 Remmarguts' Date(第K短路问题 Dijkstra+A*)
http://poj.org/problem?id=2449 Remmarguts' Date Time Limit: 4000MS Memory Limit: 65536K Total Subm ...
- (poj)3268 Silver Cow Party 最短路
Description One cow ≤ N ≤ ) conveniently numbered ..N ≤ X ≤ N). A total of M ( ≤ M ≤ ,) unidirection ...
- POJ 3662 Telephone Lines【Dijkstra最短路+二分求解】
Telephone Lines Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7214 Accepted: 2638 D ...
随机推荐
- 【NOIP2016提高A组模拟9.9】运输妹子
题目 小轩轩是一位非同一般的的大农(lao)场(si)主(ji),他有一大片非同一般的农田,并且坐落在一条公路旁(可以认为是数轴),在他的农田里种的东西也非同一般--不是什么水稻小麦,而是妹子. 在小 ...
- linux查杀minergate-cli/minerd病毒
redis的漏洞让公司的服务器中了挖矿的病毒,入侵者在服务器上留了后门.每次只是把进程杀杀,但是过段时间病毒又回来了,这个事情一直让人头疼.先是minerd的病毒入侵,后是minergate-cli入 ...
- python 面向对象_2
self的理解 通俗理解self就是实例对象,实例化的是什么,self就是什么 实例变量: 经过实例化才能使用的变量 class Person(): def __init__(self,id,name ...
- XML 属性
XML 属性 从 HTML,你会回忆起这个:<img src="computer.gif">."src" 属性提供有关 <img> 元素 ...
- docker-compose安装xxl-job
docker能安装的docker-compose肯定就能安装,锻炼一下写yml的能力. 后面再具体写实际中的应用 [root@localhost mysql]# cat docker-compose. ...
- (53)LINUX应用编程和网络编程之八Linux网络基础
3.8.1.网络通信概述 3.8.1.1.从进程间通信说起:网络域套接字socket,网络通信其实就是位于网络中不同主机上面的2个进程之间的通信. 3.8.1.2.网络通信的层次 (1)硬件部分:网卡 ...
- vue树形菜单
vue树形菜单 由于项目原因,没有使用ui框架上的树形菜单,所以自己动手并参考大佬的代码写了一个树形菜单的组件,话不多说,直接上代码.html代码js代码直接调用api 把请求到的数据直接赋值给per ...
- Phaser3 场景Scene之间的传值 -- HTML网页游戏开发
一.首先当然得有至少有二个场景sceneA.js,sceneB.js 二.从场景A传值到场景B二种方法 1)通过事件this.events.emit('event key',{objKey:objVa ...
- DjangoRestFrameWork 版本控制
DRF的版本控制 为什么需要版本控制 API 版本控制允许我们在不同的客户端之间更改行为(同一个接口的不同版本会返回不同的数据). DRF提供了许多不同的版本控制方案. 可能会有一些客户端因为某些原因 ...
- java第二周小结
这是接触Java的第一周,了解这个语言的一些基础知识,下面是对这段时间重要知识点的汇总 一.Java是一种面向对象的语言 特点为:简洁高效.可移植性.适合分布式计算.健壮防患于未然的特性.多线程 ...