题意

在平面直角坐标系上,你有一只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. 为什么我们要使用DTO

    基础结构解释 UI-表现层-与控制器打交道(UI向Controller 传递数据时使用DTO(数据传输对象)) Service-应用服务层 Domain 领域对象 DTO 数据传输对象,一般只包含基础 ...

  2. 关于instanface的问题

    nstanceof关键字来判断某个对象是否属于某种数据类型.报错  代码如下 package cn.lijun.demo3; import cn.lijun.demo.Person;import cn ...

  3. KEIL5.11安装小结

    一.注意点 1.安装路径不能带中文,必须是英文路径 2.安装目录不能跟 51 的 KEIL 或者 KEIL4 冲突,三者目录必须分开 3.KEIL5 不像 KEIL4 那样自带了很多厂商的 MCU 型 ...

  4. 更新到@vue/cli 4.1.1版本的前端开发前的准备

    一.概念简述 1.node.js目的是提供一个JS的运行环境. 2.npm(node package manager)是一个JS包管理器. 二.检查自己的电脑是否已安装相关配置 1.查看node.js ...

  5. 大数据基石——Hadoop与MapReduce

    本文始发于个人公众号:TechFlow 近两年AI成了最火热领域的代名词,各大高校纷纷推出了人工智能专业.但其实,人工智能也好,还是前两年的深度学习或者是机器学习也罢,都离不开底层的数据支持.对于动辄 ...

  6. JVM系列(三):java的垃圾回收机制

    java垃圾回收机制介绍    上一篇讲述了JVM的内存模型,了解了到了绝大部分的对象是分配在堆上面的,我们在编码的时候并没有显示的指明哪些对象需要回收,但是程序在运行的过程中是会一直创建对象的,之所 ...

  7. ACM北大暑期课培训第五天

    今天讲的扫描线,树状数组,并查集还有前缀树. 扫描线   扫描线的思路:使用一条垂直于X轴的直线,从左到右来扫描这个图形,明显,只有在碰到矩形的左边界或者右边界的时候,这个线段所扫描到的情况才会改变, ...

  8. 【转】python中查询某个函数的使用方法

    使用help(),例查询sum函数的用法 使用官方文档: 1)打开python的IDLE: 2)点击help,选择python doc(这是python的官方文档,或者你也可以直接按f1键) 3)在调 ...

  9. Spring AOP 基于AspectJ

    简介 AspectJ是一个基于Java语言的AOP框架,Spring2.0以后新增了对AspectJ切点表达式支持.因为Spring1.0的时候Aspectj还未出现; AspectJ1.5中新增了对 ...

  10. sparkstreaming消费kafka后bulk到es

    不使用es-hadoop的saveToES,与scala版本冲突问题太多.不使用bulkprocessor,异步提交,es容易oom,速度反而不快.使用BulkRequestBuilder同步提交. ...