您的位置:首页 > 其它

图论/最短路径

2011-08-15 11:30 417 查看
pku3072:题目大意,给定n个点,求一个机器人从点1到点n的最少用时,机器人每步走过的距离不能超过r,沿着某个方向到达一个点后,如果想到达另一个点,那么需要转过一定的角度朝向那个点才行(可能转过0度)。

解法:最短路径DP,令dis[v][u]表示从起点1经过某些顶点后到达u,再到达v的最短用时,则dis[v][u] = Min{d[v][u], dis[u][j]+map[u][v]+turnDis(p[j], p[u], p[v])}。

方程比较简单,关键是turnDis(p[j],p[u],p[v])怎么算,也就是说转过的角度。我是这么做的,假设p[j]->p[u]形成向量(x1,y1),p[u]->p[v]形成向量(x2,y2),那么向量夹角为atan2(y2,x2)-atan2(y1,x1),不过这样算出的夹角可能大于pi,这个时候取2*pi-(atan2(y2,x2)-atan2(y1,x1))就可以了。

测试数据地址:http://ai.stanford.edu/~chuongdo/acm/2006/

View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
usingnamespace std;

constint N =1010;
constint M =20100;

int n, m, k, tot, dis
, h
, v[M], nxt[M], w[M];
bool visit
;

queue <int> q;

void add(int a, int b, int c)
{
v[tot] = b;
w[tot] = c;
nxt[tot] = h[a];
h[a] = tot++;
}

bool spfa(int limit)
{
int u, i, tmp;
while(!q.empty())  q.pop();
memset(visit, false, sizeof(visit));
memset(dis, -1, sizeof(dis));
q.push(1);
dis[1] =0;
while(!q.empty())
{
u = q.front();
q.pop();
visit[u] =false;
for(i = h[u]; i !=-1; i = nxt[i])
{
if(w[i] > limit)  tmp =1;
else  tmp =0;
if(dis[v[i]]==-1|| dis[v[i]]>dis[u]+tmp)
{
dis[v[i]] = dis[u] + tmp;
if(!visit[v[i]])
{
visit[v[i]] =true;
q.push(v[i]);
}
}
}
if(dis
!=-1&& dis
<=k)  returntrue;
}
returnfalse;
}

int main()
{
int i, a, b, c, l, r, mid, ans;
scanf("%d%d%d", &n, &m, &k);
tot =0;
r =-1;
memset(h, -1, sizeof(h));
for(i =0; i < m; i++)
{
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
r = max(r, c);
}
l =0;
ans =-1;
while(l <= r)
{
mid = (l+r) >>1;
if(spfa(mid))
{
ans = mid;
r = mid-1;
}
else  l = mid+1;
}
printf("%d\n", ans);
return0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: