图论/最短路径

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 <cmath>#include <queue>#include <cstring>usingnamespace std;constint N =25;constdouble eps = 1e-6;constdouble pi = acos(-1);struct node{    double x, y;}p[N];int n;double r, dis[N][N], map[N][N];bool visit[N];queue <int> q;double Dis(const node &a, const node &b){    double x, y;    x = b.x - a.x;    y = b.y - a.y;    return  sqrt(x*x+y*y);}int dbcmp(double x){    if(x > eps)  return1;    elseif(x <-eps)  return-1;    elsereturn0;}double turnDis(node p0, node p1, node p2){    double x1, y1, x2, y2, tmp;    x1 = p1.x - p0.x;    y1 = p1.y - p0.y;    x2 = p2.x - p1.x;    y2 = p2.y - p1.y;    //double tmp1 = atan2(y2, x2);    //double tmp2 = atan2(y1, x1);    tmp = fabs(atan2(y2,x2)-atan2(y1,x1));    if(tmp > pi)  tmp =2*pi-tmp;    return  tmp*180.0/pi;}void spfa(){    int u, i, j;    double tmp;    while(!q.empty())  q.pop();    q.push(1);    memset(visit, false, sizeof(visit));    while(!q.empty())    {        u = q.front();        q.pop();        visit[u] =false;        for(i =1; i <= n; i++)            if(i!=u && dbcmp(map[u][i]-r)<=0)                for(j =0; j <= n; j++)                {                    if(j==0&& u!=1)  continue;                    if(j!=i && dbcmp(dis[u][j]) >=0)                    {                        tmp = turnDis(p[j],p[u],p[i]);                        if(dis[i][u]<0|| dbcmp(dis[i][u]-(dis[u][j]+tmp+map[u][i]))>0)                        {                            dis[i][u] = dis[u][j]+tmp+map[u][i];                            if(!visit[i])                            {                                q.push(i);                                visit[i] =true;                            }                        }                    }                }    }}int main(){    int i, j;    double ans;    while(scanf("%lf%d", &r, &n) != EOF)    {        if(n ==-1)  break;        for(i =1; i <= n; i++)  scanf("%lf%lf", &p[i].x, &p[i].y);        p[0].x = p[1].x-(p[n].x-p[1].x);        p[0].y = p[1].y-(p[n].y-p[1].y);        for(i =1; i <= n; i++)            for(j =0; j <= n; j++)            {                dis[j][i] =-1.0;                map[i][j] = Dis(p[i], p[j]);            }        dis[1][0] =0;        spfa();        ans =-1.0;        for(j =1; j < n; j++)            if(dbcmp(dis[n][j])>=0&& (ans<0|| dbcmp(ans-dis[n][j])>0))                ans = dis[n][j];        if(ans <0)  printf("impossiblen");        else  printf("%.0fn", ans);    }    return0;}

pku3662:题目大意,给定一个无向加权图,求从顶点1到顶点n的一条路径,其中有k条边的费用可以给你报销,求使不能被报销的边的最大值最小~

解法:这种题,一看题目让求的量基本上知道八成就是二分。这个题确实也是二分~二分那个最小值limit,然后求从顶点1到顶点n最少需要经过多少条边权大于limit的边。

花了20+分钟小水了一下~看会儿电视去~用G++47ms,900+k内存,C++交了一次32ms,400+k内存,竟然还排在rank 2。。。
图论/最短路径图论/最短路径View Code

#include <iostream>#include <cstdio>#include <cstring>#include <queue>usingnamespace std;constint N =1010;constint M =20100;int n, m, k, tot, dis[N], h[N], v[M], nxt[M], w[M];bool visit[N];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[n]!=-1&& dis[n]<=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("%dn", ans);    return0;}

原文链接: https://www.cnblogs.com/zxndgv/archive/2011/08/15/2139151.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/30547

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 上午7:52
下一篇 2023年2月8日 上午7:53

相关推荐