zoukankan      html  css  js  c++  java
  • 游戏:最短路,拆点

    把问题抽象成图论应该不难(也许都不用抽象?),但是怎么建边怎么跑就千差万别了。

    首先应该注意到的一点是坐标的范围是0~500,也就是501*501个位置,所以数组/队列不要开小。

    另外题目给出的莉露露没说位置不能重复,所以每个点可能不止入队一次,仍然要注意数组大小。

    刚开始一直在想复杂度与n挂钩的算法,但是它挂了。

    可以发现,n与x*y的差距并不打,所以如果正解复杂度可接受n的话那么拿xy作为复杂度应该没有问题。

    先大概讲一下考场上的暴力(80分,因为上面说的锅,把数组开大是88分):

    考虑每个莉露露的行动:去一个位置,捡起由岐,走几步,扔出去。

    如果我们要对于每一个格子进行转移而不是针对每一个莉露露的话,去一个位置捡起由岐这个操作就可以变成:

    找到最近的莉露露来这个位置,再让这个莉露露去走,扔。

    走和扔的话就能比较简单的转移了。

    那么首先的一个问题是,怎么找到离每一个点最近的莉露露有多远?

    所有的二维几何题都可以用KD-tree乱搞。貌似的确可以这也是我考场上打了一半的思路。

    但是这其实就是一个BFS,以每一个莉露露为源点不断扩散直至每个点都会被搜索到一次。

    复杂度O(xy)。可以考虑建一个超级源点其距离值为-1,由它连向每一个莉露露,当然也可以直接搞。

    然后假如我们已经找到了这个数组叫nst吧,那么怎么跑最短路?

    我们假设由岐始终没着地:在被扔之前另一个莉露露已经到了落点去准备接住了。(当然不会影响答案)

    那么她就始终在莉露露的手里了,所有的莉露露只有两种操作。

    1.走一步,费用C,那么就想四周连边(不用真的建边直接for枚举就行)。连4条边。

    2.扔。目的地只能是本行或本列上的,还是枚举,连了x+y条边。

    而因为我们假设不让由岐落地,所以在到了目的地之后还要让最近的莉露露来接住她,费用就是ax+b+c*nst[tx][ty]

    所以总边数是x3级别的,复杂度也是。

    另外还可以优化一下,如果你是被从这一列扔过来的,那么你不会再被扔到这一列,行同理,开一个bool数组更新最小距离时记录就好。

    这样的话边数能减少一些,具体多少看测试点,反正效果还可以。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<queue>
     5 using namespace std;
     6 const int xx[]={1,0,0,-1},yy[]={0,1,-1,0};
     7 #define tx qx[h]+xx[i]
     8 #define ty qy[h]+yy[i]
     9 struct ps{int x,y;long long d;friend bool operator<(ps a,ps b){return a.d>b.d;}};
    10 priority_queue<ps>q;
    11 bool l[505][505],r[505][505];
    12 int com,nst[505][505],X,Y,n,qx[500155],qy[500155],gx,gy,sx,sy;
    13 long long a,b,c,dt[505][505];
    14 signed main(){//freopen("ex_game5.in","r",stdin);
    15     memset(nst,0x3f,sizeof nst);memset(dt,0x3f,sizeof dt);
    16     scanf("%d%d%lld%lld%lld%d%d%d",&X,&Y,&a,&b,&c,&n,&sx,&sy);
    17     nst[sx][sy]=0,qx[1]=sx,qy[1]=sy;
    18     for(int i=2;i<=n;++i)scanf("%d%d",&gx,&gy),nst[gx][gy]=0,qx[i]=gx,qy[i]=gy;
    19     for(int h=1,t=n;h<=t;++h)for(int i=0;i<=3;++i)
    20         if(tx>=0&&ty>=0&&tx<=X&&ty<=Y&&nst[tx][ty]>nst[qx[h]][qy[h]]+1)
    21             ++t,nst[qx[t]=tx][qy[t]=ty]=nst[qx[h]][qy[h]]+1;//,printf("%lld %lld
    ",sx,sy);
    22     q.push((ps){sx,sy,dt[sx][sy]=0});
    23     while(!q.empty()){
    24         int x=q.top().x,y=q.top().y;long long d=q.top().d;q.pop();
    25         if(dt[x][y]!=d)continue;
    26         if(x==gx&&y==gy){printf("%lld
    ",d);return 0;}
    27         #define kx x+xx[i]
    28         #define ky y+yy[i]
    29         for(int i=0;i<=3;++i)if(kx>=0&&kx<=X&&ky<=Y&&ky>=0&&dt[kx][ky]>d+c)
    30             l[kx][ky]=r[kx][ky]=0,q.push((ps){kx,ky,dt[kx][ky]=d+c});
    31         if(!l[x][y])for(int i=0;i<x;++i)if(dt[i][y]>d+a*(x-i)+b+c*nst[i][y])
    32             l[i][y]=1,r[i][y]=0,q.push((ps){i,y,dt[i][y]=d+a*(x-i)+b+c*nst[i][y]});
    33         if(!l[x][y])for(int i=x+1;i<=X;++i)if(dt[i][y]>d+a*(i-x)+b+c*nst[i][y])
    34             l[i][y]=1,r[i][y]=0,q.push((ps){i,y,dt[i][y]=d+a*(i-x)+b+c*nst[i][y]});
    35         if(!r[x][y])for(int i=0;i<y;++i)if(dt[x][i]>d+a*(y-i)+b+c*nst[x][i])
    36             r[x][i]=1,l[x][i]=0,q.push((ps){x,i,dt[x][i]=d+a*(y-i)+b+c*nst[x][i]});
    37         if(!r[x][y])for(int i=y+1;i<=Y;++i)if(dt[x][i]>d+a*(i-y)+b+c*nst[x][i])
    38             r[x][i]=1,l[x][i]=0,q.push((ps){x,i,dt[x][i]=d+a*(i-y)+b+c*nst[x][i]});
    39     }
    40 }
    View Code

    100%算法就是稍微优化了一下建边。

    稍微改变状态定义,其实每次被扔出去可以被分为两个阶段,从那个ax+b能yy一下。

    首先花费b的费用起飞,然后沿着一个方向飞,每飞一个格子的费用是a,着陆的费用就是最近的莉露露捡起她的费用c×nst。

    当然也可以不飞,一步一步走,这里和暴力是一样的。

    那么因为被扔的操作每次也只会向上下左右四个格子转移了,所以复杂度有了保证。

    然而你现在需要弄清楚她有没有起飞有没有着陆,如果在飞的话她是在横着飞还是竖着。

    拆点,拆成3个,分别表示0在地上,1在横着飞,2在竖着飞。

    可以从0转移到1和2,费用为b。

    可以从1,2转移到0,费用为c×nst。

    可以从0转移到相邻4个格子的0,费用为c。

    可以从1转移到左右两个格子的1,费用为a。

    可以从2转移到上下两个格子的2,费用为a。

    总边数10n2。跑Dijkstra,复杂度乘个log,问题不大。

    据secret测试可以暴力把所有边都建出来也能A,但是不推荐大常数者使用。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<queue>
     5 #include<ctime>
     6 using namespace std;
     7 const int xx[]={1,-1,0,0},yy[]={0,0,-1,1};
     8 #define tx qx[h]+xx[i]
     9 #define ty qy[h]+yy[i]
    10 struct ps{int x,y,st;long long d;friend bool operator<(ps a,ps b){return a.d>b.d;}};
    11 priority_queue<ps>q;
    12 int com,X,Y,n,qx[500155],qy[500155],gx,gy,sx,sy;
    13 long long a,b,c,dt[3][505][505],nst[505][505];
    14 signed main(){//freopen("ex_game5.in","r",stdin);
    15     memset(nst,0x3f,sizeof nst);memset(dt,0x3f,sizeof dt);
    16     scanf("%d%d%lld%lld%lld%d%d%d",&X,&Y,&a,&b,&c,&n,&sx,&sy);
    17     nst[sx][sy]=0,qx[1]=sx,qy[1]=sy;
    18     for(int i=2;i<=n;++i)scanf("%d%d",&gx,&gy),nst[gx][gy]=0,qx[i]=gx,qy[i]=gy;
    19     for(int h=1,t=n;h<=t;++h)for(int i=0;i<=3;++i)
    20         if(tx>=0&&ty>=0&&tx<=X&&ty<=Y&&nst[tx][ty]>nst[qx[h]][qy[h]]+c)
    21             nst[qx[++t]=tx][qy[t]=ty]=nst[qx[h]][qy[h]]+c;
    22     q.push((ps){sx,sy,0,dt[0][sx][sy]=0});
    23     while(!q.empty()){
    24         int x=q.top().x,y=q.top().y,st=q.top().st;long long d=q.top().d;q.pop();
    25         if(dt[st][x][y]!=d)continue;
    26         if(x==gx&&y==gy){printf("%lld
    ",d);return 0;}
    27         #define kx x+xx[i]
    28         #define ky y+yy[i]
    29         if(!st){
    30             for(int i=0;i<=3;++i)if(kx>=0&&kx<=X&&ky<=Y&&ky>=0&&dt[0][kx][ky]>d+c)
    31                 q.push((ps){kx,ky,0,dt[0][kx][ky]=d+c});
    32             for(int s=1;s<=2;++s)if(dt[s][x][y]>d+b)
    33                 q.push((ps){x,y,s,dt[s][x][y]=d+b});
    34         }else{
    35             for(int i=st*2-2;i<=st*2-1;++i)if(kx>=0&&kx<=X&&ky<=Y&&ky>=0&&dt[st][kx][ky]>d+a)
    36                 q.push((ps){kx,ky,st,dt[st][kx][ky]=d+a});
    37             if(dt[0][x][y]>d+nst[x][y])q.push((ps){x,y,0,dt[0][x][y]=d+nst[x][y]});
    38         }
    39     }
    40 }
    代码复杂度不大,1.5k
  • 相关阅读:
    JavaScript中的数据类型转换
    JavaScript中的变量
    set_uid set_gid stick_bit 软硬链接
    chmod、chown、umask、lsattr/chattr
    环境变量、cp、mv、cat 等命令
    相对和绝对路径 mkdir cd rm 等命令
    linux 系统 目录,以部分及相关命令
    单用户模式 和救援模式 、以及相互登陆(免密)
    putty 、xshell的使用 和 putty 、xshell、 shell 间免密登陆
    vmware NAT 网络出现问题的解决方法
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11461203.html
Copyright © 2011-2022 走看看