[NOI2011 智能车比赛]

[关键字]:计算几何

[题目大意]:http://221.192.240.123:8586/JudgeOnline/showproblem?problem_id=1668

//=====================================================================================================

[分析]:计算几何题,需要有清晰的思维(本人就是一开始没想清楚)。从每一个矩形的顶点包括起点开始检查能不能到其它点,并记录长度。因为最短路径上的点一定是在矩形的顶点上,而且因为是不断往前走,所以可以用dp来做最短路。检查方法就是先假定一个视野的上下界,然后检查每个顶点是否在视野范围内(叉积),在就更新距离。然后从每个矩形交界处开始判断是否会阻挡视野,会就更新上下界,直到视野为0或检查到终点所在矩形(此时更新答案)。当所有点都做完后就可以找到答案。

[代码]:

View Code
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define sqr(x) (double(x) * (x))
#define MAXN 10000
#define INF 1e100

struct point
{
int x,y;
}a,b,c,d,S,T;
struct rectangle
{
point a,b,c,d;
}rec[MAXN];
int n;
double v,ans=INF;
double f[MAXN];

void Init()
{
int t1,t2,t3,t4;
scanf("%d",&n);
for (int i=0;i<n;i++)
{
scanf("%d%d%d%d",&t1,&t2,&t3,&t4);
rec[i].a.x=t1,rec[i].a.y=t2;
rec[i].b.x=t1,rec[i].b.y=t4;
rec[i].c.x=t3,rec[i].c.y=t2;
rec[i].d.x=t3,rec[i].d.y=t4;
//printf("%d %d %d %d %d %d %d %d\n",rec[i].a.x,rec[i].a.y,rec[i].b.x,rec[i].b.y,rec[i].c.x,rec[i].c.y,rec[i].d.x,rec[i].d.y);
}
scanf("%d%d",&S.x,&S.y);
scanf("%d%d",&T.x,&T.y);
scanf("%lf",&v);
if (S.x>T.x) swap(S,T);
for (int i=0;i<n*4;i++) f[i]=INF;
return;
}

double dis(point a,point b)
{
return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}

long long cross(point a,point b,point c,point d)
{
return (long long)(b.x-a.x)*(d.y-c.y)-(long long)(d.x-c.x)*(b.y-a.y);
}

bool cleck(point a,point b,point upper,point lower)
{
if (b.x<a.x) return 0;
if (cross(a,lower,a,b)<0) return 0;
if (cross(a,upper,a,b)>0) return 0;
return 1;
}

void Work(point start,int now,double val,double &ans)
{
if (val>=INF) return;
point lower,upper;
lower.x=start.x,lower.y=start.y-1;
upper.x=start.x,upper.y=start.y+1;
for (int i=now;i<n;i++)
{
if (cleck(start,rec[i].a,upper,lower))
f[i*4]=min(f[i*4],val+dis(start,rec[i].a));

if (cleck(start,rec[i].b,upper,lower))
f[i*4+1]=min(f[i*4+1],val+dis(start,rec[i].b));

if (cleck(start,rec[i].c,upper,lower))
f[i*4+2]=min(f[i*4+2],val+dis(start,rec[i].c));

if (cleck(start,rec[i].d,upper,lower))
f[i*4+3]=min(f[i*4+3],val+dis(start,rec[i].d));

if (rec[i].a.x<=T.x && T.x<=rec[i].d.x)
if (rec[i].a.y<=T.y && T.y<=rec[i].d.y)
if (cleck(start,T,upper,lower))
ans=min(ans,val+dis(start,T));
if (i+1<n)
{
point l,r;
l.x=rec[i].c.x,l.y=max(rec[i].c.y,rec[i+1].a.y);
r.x=rec[i].d.x,r.y=min(rec[i].d.y,rec[i+1].b.y);
//printf("%d %d %d %d\n",l.x,l.y,r.x,r.y);
if (rec[i].c.x==start.x)
{
if (l.y>start.y || start.y>r.y)
{
f[(i+1)*4]=min(f[(i+1)*4],val+dis(start,rec[i+1].a));
f[(i+1)*4+1]=min(f[(i+1)*4+1],val+dis(start,rec[i+1].b));
return;
}
}
else
{
if (cross(start,lower,start,l)>0) lower.x=l.x,lower.y=l.y;
if (cross(start,upper,start,r)<0) upper.x=r.x,upper.y=r.y;
if (cross(start,upper,start,lower)>0) return;
}
}
}
return;
}

void Solve()
{
for (int i=0;i<n;i++)
{
if (rec[i].a.x<=S.x && S.x<=rec[i].d.x)
if (rec[i].a.y<=S.y && S.y<=rec[i].d.y)
Work(S,i,0,ans);
Work(rec[i].a,i,f[i*4],ans);
Work(rec[i].b,i,f[i*4+1],ans);
Work(rec[i].c,i,f[i*4+2],ans);
Work(rec[i].d,i,f[i*4+3],ans);
}
//for (int i=0;i<n*4;i++) printf("%d %f\n",i,f[i]);
printf("%0.10lf\n",ans/v);
return;
}

int main()
{
Init();
Solve();
system("pause");
return 0;
}



转载于:https://www.cnblogs.com/procedure2012/archive/2012/02/16/2354094.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值