题意

在平面直角坐标系上,你有一只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. POJ1741 点分治模板

    传送门:http://poj.org/problem?id=1741 题意: 求树上两点间路径长度小于k的点对个数 题解: 参考资料 守望的淀粉质略解:https://www.luogu.org/bl ...

  2. codeforces 540E 离散化技巧+线段树/树状数组求逆序对

    传送门:https://codeforces.com/contest/540/problem/E 题意: 有一段无限长的序列,有n次交换,每次将u位置的元素和v位置的元素交换,问n次交换后这个序列的逆 ...

  3. ABP运行Login failed for user 'IIS APPPOOL XXXXX Reason: Could not find a login matching the name provided问题解决

    我们在ABP官网上面生成解决方案后,编译完成,将数据库连接字符串中的Ip改成自己的测试数据库Ip直接在Vs里面调试运行没有任何问题. 发布之后到文件夹后运行,就报如下图异常. VS里面可以跑起来,单独 ...

  4. python监控模块

    pip install psutil 获取内存信息: >>> import psutil >>> mem = psutil.virtual_memory() #获取 ...

  5. PLsql下载官网下载地址

    https://www.allroundautomations.com/registered/plsqldev.html

  6. 聊聊最近撸Spring源码感悟

    一.前言     最近一段时间撸了Spring IOC.AOP.Transactional源码,这篇文章聊聊我写了哪些小玩意,这可能就是阅读源码以后最大收获.希望大家在里面能学习一些什么东西吧: 二. ...

  7. 0015 行高那些事:line-height

    目标 理解 能说出 行高 和 高度 三种关系 能简单理解为什么行高等于高度单行文字会垂直居中 应用 使用行高实现单行文字垂直居中 能会测量行高 3.1 行高测量 行高的测量方法: 3.2 单行文本垂直 ...

  8. 002 ceph的deploy部署

    介绍:前期对ceph有一个简单的介绍,但是内容太大,并不具体,接下来使用ceph-deploy部署一个Ceph集群,并做一些运维管理工作,深入的理解Ceph原理及工作工程! 一.环境准备 本次使用的虚 ...

  9. vc++栈的简单实现

    栈的数据类型是先进后出 #ifndef __MYSTACK__ #define __MYSTACK__ #include <Windows.h> typedef struct Node { ...

  10. $loj$10222 佳佳的$Fibonacci$ 矩阵快速幂

    正解:矩阵快速幂 解题报告: 我永远喜欢loj! 一看到这个就应该能想到矩阵快速幂? 然后就考虑转移式,发现好像直接想不好想,,,主要的问题在于这个*$i$,就很不好搞$QAQ$ 其实不难想到,$\s ...