题意

在平面直角坐标系上,你有一只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的更多相关文章

  1. July 【补题】

    A(zoj 3596) bfs,记忆搜都可以, 按余数来记录状态. B(zoj 3599) 博弈,跳过 C(zoj 3592) 简单dp,题意不好懂 D(zoj 3602) 子树哈希, 对根的左右儿子 ...

  2. [转] POJ计算几何

    转自:http://blog.csdn.net/tyger/article/details/4480029 计算几何题的特点与做题要领:1.大部分不会很难,少部分题目思路很巧妙2.做计算几何题目,模板 ...

  3. ACM计算几何题目推荐

    //第一期 计算几何题的特点与做题要领: 1.大部分不会很难,少部分题目思路很巧妙 2.做计算几何题目,模板很重要,模板必须高度可靠. 3.要注意代码的组织,因为计算几何的题目很容易上两百行代码,里面 ...

  4. UOJ #277 BZOJ 4739 定向越野 (计算几何、最短路)

    手动博客搬家: 本文发表于20181208 14:39:01, 原地址https://blog.csdn.net/suncongbo/article/details/84891710 哇它居然显示出图 ...

  5. ACM/ICPC 之 计算几何入门-叉积-to left test(POJ2318-POJ2398)

    POJ2318 本题需要运用to left test不断判断点处于哪个分区,并统计分区的点个数(保证点不在边界和界外),用来做叉积入门题很合适 //计算几何-叉积入门题 //Time:157Ms Me ...

  6. [leetcode] 题型整理之图论

    图论的常见题目有两类,一类是求两点间最短距离,另一类是拓扑排序,两种写起来都很烦. 求最短路径: 127. Word Ladder Given two words (beginWord and end ...

  7. HDU 2202 计算几何

    最大三角形 Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  8. ACM 计算几何中的精度问题(转)

    http://www.cnblogs.com/acsmile/archive/2011/05/09/2040918.html 计算几何头疼的地方一般在于代码量大和精度问题,代码量问题只要平时注意积累模 ...

  9. hdu 2393:Higher Math(计算几何,水题)

    Higher Math Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

随机推荐

  1. buerdepepeqi 的模版

    buerdepepeqi的模板 头文件 #include <set> #include <map> #include <deque> #include <qu ...

  2. 小心Powershell的位数

    我们都知道64位的 Windows 中有两个Powershell,32位的 Windows Powershell(x86)和64位的 Windows Powershell.(当然,32位的Window ...

  3. 第三阶段:3.Web端产品设计:4.产品设计-交互设计

    交互设计主要做框架层以及结构层.包括交互关系,信息结构,界面布局,导航设计,信息内容. 导航关系非常重要. 这是框架层. 这是结构层. 要素就是信息内容.

  4. JVM之GC回收信息详解

    一.-XX:+PrintGCDetails 打印GC日志 参数配置:-Xms10M -Xmx10M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+Pr ...

  5. 大数据学习之路-phoenix

    1.phoenix安装 ------------------ 1.安装phoenix a)下载apache-phoenix-4.10.0-HBase-1.2-bin.tar.gz   下载网址:htt ...

  6. 「洛谷P3469」[POI2008]BLO-Blockade 解题报告

    P3469[POI2008]LO-Blockade 题意翻译 在Byteotia有n个城镇. 一些城镇之间由无向边连接. 在城镇外没有十字路口,尽管可能有桥,隧道或者高架公路(反正不考虑这些).每两个 ...

  7. git 汇总

  8. 天天都在用Git,那么你系统学习过吗?(一)学习过程

    你系统学习Git了吗? 使用Mac编程的好处,不是因为Mac长得好看 Git内容学习准备 如果你还没有用Git,就不要写代码了. GitHub仓库的使用. 新员工入职的时候,会让他先用一周的时间去学习 ...

  9. 【Java并发基础】并发编程bug源头:可见性、原子性和有序性

    前言 CPU .内存.I/O设备之间的速度差距十分大,为了提高CPU的利用率并且平衡它们的速度差异.计算机体系结构.操作系统和编译程序都做出了改进: CPU增加了缓存,用于平衡和内存之间的速度差异. ...

  10. 最近发现Git的速度好慢

    最近发现Git速度好慢,Git Bash要等5秒左右才能操作,网上查了查原因,说是火绒的问题,哎平时也用不到,看日志一个毒都没光顾过我电脑,火绒卸载! 卸了后果然快多了