[计算几何+图论]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 ...
随机推荐
- 【Linux】centos查看防火墙是否关闭
查看防火墙的状态的命令为: sudo systemctl status firewalld 打开防火墙的方式有两种,一种是打开后重启会恢复回原来的状态,命令为: sudo systemctl star ...
- Channel 9视频整理【2】
JadeChang https://channel9.msdn.com/Niners/JadeChang 繁体中文视频 2016 Nano Server / Docker / Containers 打 ...
- The third day of Crawler learning
连续爬取多页数据 分析每一页url的关联找出联系 例如虎扑 第一页:https://voice.hupu.com/nba/1 第二页:https://voice.hupu.com/nba/2 第三页: ...
- linux-iostat、sar、top、htop
1.iostat 实时显示linux的任务 centos7中默认没有安装iostat,所以得提前安装sysstat yum install -y sysstat -c 统计cpu信息 -d 统计磁盘信 ...
- 7.13 Python基础语法
Python基础语法 编码: 默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串. 当然你也可以为源码文件指定不同的编码 python2.7中有两个函数 ...
- Python 愤怒的小鸟代码实现:物理引擎pymunk使用
游戏介绍 最近比较忙,周末正好有时间写了python版本的愤怒的小鸟,使用了物理引擎pymunk,图片资源是从github上下载的,实现了一个可玩的简单版本. 功能实现如下: 支持小鸟类型:红色小鸟, ...
- Go指针,如此轻松掌握,希望有收获
开篇语 依稀记得大学必修课,C语言中的指针,简直是噩梦,指来指去,有没有晕乎乎的感觉,我在想是不是也因为如此,所以Java语言的开发者C才比C语言的多,Java正因为解决了C的痛点,所以今天才能变成语 ...
- Mysql 性能优化Explain详解
explain 功能我们在日常使用中,使用慢查询找到执行时间比较久的查询,然后使用SHOW STATUS.SHOW PROFILE.和explain做单条语句的分析.使用explain关键字可以模拟优 ...
- nginx 负载均衡及反向代理
Nginx简介 Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器.由俄罗斯的程序设计师开发,官方测试nginx能够支支撑5万并发链接,并且cpu.内存 ...
- C# 删除指定文件
using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Text;us ...