[计算几何+图论]doge
题意
在平面直角坐标系上,你有一只doge在原点处。doge被绳子拴住了,绳子不会打结,没有弹性(但很柔软),并且长度为L。平面上有一些目标,因此你的doge会按照顺序去捡起它们,但是doge只能走直线。此外平面上还有一些障碍,视为一些点,狗在绕圈时可能会把绳子缠在上面。问L的最小值。
坐标均为整数,所有数的绝对值都不超过1000。物品和障碍物数量和不超过100。
“缠绕”:
、

注意,虽然画的物品和障碍物是一个圈,但实际上可看做一个点。
思考
一些性质:
1.乱套模板是不可做的。
2.答案为doge依次捡起1~i物品中,绳子能缩短的最大值。因为doge可以沿这个能缩短的路径走,捡起一个物品后能回溯到原点。
3.doge在以此捡起1~i的物品中,doge一定会走最短路。因为这才更有可能使答案更优。
4.最短的路径是不能乱走的,但仿佛与两点与线段的位置有关。
先将所有点旋转一个角度,使得他们都不在同一条与x轴垂直的线上。

红线是doge可能走的路径。而这个答案为所有红线绷紧后的长度。
而此时对于有经过顺序的红线,它是否弯折,怎么弯折,只跟它现在经过某个障碍物上下面的顺序有关(图中的上下是黑色圈的上部分线段和下部分线段)。对于一个经过上下顺序相同的线段,可看做它们是等价的(虽然长度可能不同)。也就是说,若一种红线经过上下顺序已经给定,它长度的最小值就是(所有(有这种顺序的)(红线的)(长度的))最小值。
这个顺序我们可以表示成一个类似于括号序列的东西。如上图,红线必须经过的顺序为1-2-3-4-4+3+2+1+,代表了它依次经过了哪个障碍,上面还是下面。
先假我们已经会求出一个序列的答案。
5.若某次新添加一个物品后,序列最后中出现x+x+或x-x-,可将其直接删去(即倒数第二个和最后一个)。
如图:

由于1+已经在上一次中得到了走到左边的答案,又因为这一次走到了右边,所以不会受到它的影响。
6.红线的序列为一些线段的序列拼接而成。并且线段的头尾一定在障碍物或原点或终点处。
直观的想,头尾代表了一个转折点,而转折点缩紧后一定会靠着障碍物。当然也可以三角形不等式说明。
有了这些性质,我们就可以根据序列建一张图。其中每条边代表了从一个障碍物(或起点)走到另一个障碍物(或终点)所需的长度,它能在图中当且仅当这条线段以此经过障碍物的上下顺序能匹配相应位置红线的序列。从起到向终点跑最短路,即为答案。
说了这么多,其实还是要多想。
代码
#include<bits/stdc++.h>
using namespace std;
const double eps=1E-;
const double pi=acos(-);
const double INF=INT_MAX;
const int maxn=1E2+;
int q,n,m,top;
double ans,f[];
bool vis[maxn];
int size,head[];
struct pt
{
double x,y;
pt(double a=,double b=)
{
x=a,y=b;
}
void operator=(pt A)
{
x=A.x,y=A.y;
}
double operator*(pt A)
{
return x*A.y-y*A.x;
}
pt operator-(pt A)
{
return pt(x-A.x,y-A.y);
}
}target[maxn],barrier[maxn];
struct inf
{
int id,x;
inf(int a=,int b=)
{
id=a,x=b;
}
}S[];
struct edge
{
int to,next;
double w;
}E[];
//////////////////////////////////////////////////////////////////
//polygon
//////////////////////////////////////////////////////////////////
bool cmp(pt A,pt B)
{
return A.x<B.x;
}
pt rotate(pt A,double ra)
{
return pt(A.x*cos(ra)-A.y*sin(ra),A.x*sin(ra)+A.y*cos(ra));
}
int face(pt A,pt B,pt C)
{
double y=(B.y-A.y)/(B.x-A.x)*(C.x-A.x);
if(A.y+y>=C.y)
return ;
return -;
}
bool inside(pt A,pt B,pt C)
{
return min(A.x,B.x)<=C.x&&C.x<=max(A.x,B.x);
}
double dis(pt A,pt B)
{
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
int cross(pt A,pt B)
{
double d=A*B;
if(d>eps)
return ;
else
return -;
}
void push(inf A)
{
if(A.id==S[top].id&&A.x==S[top].x)
--top;
else
S[++top]=A;
}
//////////////////////////////////////////////////////////////////
//polygon
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
//graph
//////////////////////////////////////////////////////////////////
void add(int u,int v,double w)
{
E[++size].to=v;
E[size].next=head[u];
E[size].w=w;
head[u]=size;
}
void clear()
{
for(int i=;i<=top+;++i)
head[i]=;
size=;
}
double spfa()
{
for(int i=;i<=top;++i)
f[i]=INF;
f[]=;
vis[]=;
queue<int>Q;
Q.push();
while(!Q.empty())
{
int u=Q.front();
vis[u]=;
Q.pop();
for(int i=head[u];i;i=E[i].next)
{
int v=E[i].to;
double nw=E[i].w+f[u];
if(nw<f[v])
{
f[v]=nw;
if(!vis[v])
{
vis[v]=;
Q.push(v);
}
}
}
}
return f[top--];
}
bool check(int l,int r)
{
for(int i=l+;i<=r-;++i)
if(face(barrier[S[l].id],barrier[S[r].id],barrier[S[i].id])!=S[i].x)
return false;
return true;
}
double get(int x)
{
clear();
barrier[n+m+]=target[x];
push(inf(n+m+,));
for(int i=;i<=top;++i)
for(int j=i+;j<=top;++j)
if(check(i,j))
add(i,j,dis(barrier[S[i].id],barrier[S[j].id]));
for(int i=;i<=top;++i)
if(check(,i))
add(,i,dis(pt(,),barrier[S[i].id]));
return spfa();
} //////////////////////////////////////////////////////////////////
//graph
////////////////////////////////////////////////////////////////// void solve()
{
top=ans=;
cin>>n>>m;
for(int i=;i<=n;++i)
{
cin>>target[i].x>>target[i].y;
target[i].x+=0.00001;
target[i].y+=0.00001;
target[i]=rotate(target[i],pi/);
}
for(int i=;i<=m;++i)
{
cin>>barrier[i].x>>barrier[i].y;
barrier[i].x-=0.00001;
barrier[i].y-=0.00001;
barrier[i]=rotate(barrier[i],pi/);
}
sort(barrier+,barrier+m+,cmp);
pt now(,);
for(int i=;i<=n;++i)
{
if(target[i].x>now.x)
{
for(int j=;j<=m;++j)
if(inside(now,target[i],barrier[j]))
push(inf(j,face(now,target[i],barrier[j])));
}
else
{
for(int j=m;j>=;--j)
if(inside(now,target[i],barrier[j]))
push(inf(j,face(now,target[i],barrier[j])));
}
now=target[i];
double g=get(i);
ans=max(ans,g);
}
cout<<fixed<<setprecision()<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin>>q;
while(q--)
solve();
return ;
}
/*
2
8 4
2 -1
3 0
3 2
0 1
3 2
3 0
2 -1
0 0
1 0
2 0
1 1
2 1
*/ /*
5.00
*/
类似题:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1164。
[计算几何+图论]doge的更多相关文章
- July 【补题】
A(zoj 3596) bfs,记忆搜都可以, 按余数来记录状态. B(zoj 3599) 博弈,跳过 C(zoj 3592) 简单dp,题意不好懂 D(zoj 3602) 子树哈希, 对根的左右儿子 ...
- [转] POJ计算几何
转自:http://blog.csdn.net/tyger/article/details/4480029 计算几何题的特点与做题要领:1.大部分不会很难,少部分题目思路很巧妙2.做计算几何题目,模板 ...
- ACM计算几何题目推荐
//第一期 计算几何题的特点与做题要领: 1.大部分不会很难,少部分题目思路很巧妙 2.做计算几何题目,模板很重要,模板必须高度可靠. 3.要注意代码的组织,因为计算几何的题目很容易上两百行代码,里面 ...
- UOJ #277 BZOJ 4739 定向越野 (计算几何、最短路)
手动博客搬家: 本文发表于20181208 14:39:01, 原地址https://blog.csdn.net/suncongbo/article/details/84891710 哇它居然显示出图 ...
- ACM/ICPC 之 计算几何入门-叉积-to left test(POJ2318-POJ2398)
POJ2318 本题需要运用to left test不断判断点处于哪个分区,并统计分区的点个数(保证点不在边界和界外),用来做叉积入门题很合适 //计算几何-叉积入门题 //Time:157Ms Me ...
- [leetcode] 题型整理之图论
图论的常见题目有两类,一类是求两点间最短距离,另一类是拓扑排序,两种写起来都很烦. 求最短路径: 127. Word Ladder Given two words (beginWord and end ...
- HDU 2202 计算几何
最大三角形 Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- ACM 计算几何中的精度问题(转)
http://www.cnblogs.com/acsmile/archive/2011/05/09/2040918.html 计算几何头疼的地方一般在于代码量大和精度问题,代码量问题只要平时注意积累模 ...
- hdu 2393:Higher Math(计算几何,水题)
Higher Math Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
随机推荐
- Visio模具与模版
yy 这些形状就是模具 点击更多形状 然后新建模具 也可以打开已有的模具 模具名字右边有星号 代表模具未保存 鼠标右键单击可以选择保存 选择属性可以进行设置(信息之类的)也可以进行关闭 模具文件三种打 ...
- JAVA8学习——深入Comparator&Collector(学习过程)
深入Comparator&Collector 从源码深入Comparator Comparator从Java1.2就出来了,但是在1.8的时候,又添加了大量的默认方法. compare() e ...
- 非常完整的线性DP及记忆化搜索讲义
基础概念 我们之前的课程当中接触了最基础的动态规划. 动态规划最重要的就是找到一个状态和状态转移方程. 除此之外,动态规划问题分析中还有一些重要性质,如:重叠子问题.最优子结构.无后效性等. 最优子结 ...
- ssh免密登陆和加密解密
一 丶实现无密码的远程管理 1.生成公钥 私钥 [root@room9pc14 桌面]# ssh-keygen [root@room9pc14 桌面]# ls /root/.ssh/ 2.上传公钥到虚 ...
- Nginx流量复制
1. 需求 将生产环境的流量拷贝到预上线环境或测试环境,这样做有很多好处,比如: 可以验证功能是否正常,以及服务的性能: 用真实有效的流量请求去验证,又不用造数据,不影响线上正常访问: 这跟灰度发布还 ...
- Ant Design中getFieldDecorator方法的特殊用法(小bug)
记录Ant Design中getFieldDecorator方法的特殊的一个用法 了解Ant Design表单的小伙伴都知道,getFieldDecorator在大部分情况下是用来绑定一个控件的,即像 ...
- 菜鸟学习Fabric源码学习 — 背书节点和链码容器交互
Fabric 1.4 源码分析 背书节点和链码容器交互 本文档主要介绍背书节点和链码容器交互流程,在Endorser背书节点章节中,无论是deploy.upgrade或者调用链码,最后都会调用Chai ...
- linux下安装cmake方法(1)---下载压缩包
OpenCV 2.2以后的版本需要使用Cmake生成makefile文件,因此需要先安装cmake:还有其它一些软件都需要先安装cmake 1.在linux环境下打开网页浏览器,输入网址:http:/ ...
- 基于Spring封装的Javamail实现邮件发送
1.依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spring- ...
- MQ使用:apollo和rabbitmq
apollo apollo 是一个更快.更可靠.更容易维护的消息代理,它是由最初的ActiveMQ的基础构建的.它使用一个完全不同的线程和消息调度架构来实现这一点.与ActiveMQ一样,apollo ...