• UVALive 4128 Steam Roller(最短路(拆点,多状态))


    题意:模拟了汽车的行驶过程,边上的权值为全速通过所消耗的时间,而起步(从起点出发的边)、刹车(到终点结束的边)、减速(即将拐弯的边)、加速(刚完成拐弯的边)这四种不能达到全速的情况,消耗的时间为权值*2。问从起点到终点所消耗的最少时间。

    这道题主要是建图,很复杂,无耻地照着书上的代码码了一遍。让状态搞糊涂了= =

    注意:

    1、grid[][][4]记录了点的上下左右四条边的权值,id[][][4][2]记录各个点。

    2、到一个点的最短路可以是路过这个点再折返回来,e.g:1->2 c=17,2->3 c=4,从1->2的最短路为17+8+8=33<34

    3、原图总点数上限100*100,而拆点后共有8*100*100个点,狠狠地RE了一发。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<vector>
      4 #include<queue>
      5 #include<algorithm>
      6 using namespace std;
      7 
      8 const int MAXN=111111;
      9 const int maxr=111,maxc=111;
     10 const int INF =1e9;
     11 
     12 const int UP=0,LEFT=1,DOWN=2,RIGHT=3;
     13 const int inv[]={2,3,0,1};
     14 const int dr[]={-1,0,1,0};
     15 const int dc[]={0,-1,0,1};
     16 
     17 struct Edge{
     18     int u,v,c;
     19 };
     20 
     21 struct HeapNode{
     22     int c,u;
     23     bool operator < (const HeapNode rhs)const {
     24         return c>rhs.c;
     25     }
     26 };
     27 
     28 struct Dijkstra{
     29     int n,m;
     30     vector<Edge>edges;
     31     vector<int>G[MAXN];
     32     bool vis[MAXN];
     33     int d[MAXN],p[MAXN];
     34 
     35     void init(int n)
     36     {
     37         this->n=n;
     38         for(int i=0;i<n;i++)
     39             G[i].clear();
     40         edges.clear();
     41     }
     42 
     43     void add(int u,int v,int c)
     44     {
     45         edges.push_back((Edge){u,v,c});
     46         m=edges.size();
     47         G[u].push_back(m-1);
     48     }
     49 
     50     void dijkstra(int st)
     51     {
     52         priority_queue<HeapNode>q;
     53         for(int i=0;i<n;i++)
     54             d[i]=INF;
     55         d[st]=0;
     56         memset(vis,0,sizeof(vis));
     57         q.push((HeapNode){0,st});
     58         while(!q.empty())
     59         {
     60             HeapNode x=q.top();q.pop();
     61             int u=x.u;
     62             if(vis[u])
     63                 continue;
     64             vis[u]=true;
     65             int sz=G[u].size();
     66             for(int i=0;i<sz;i++)
     67             {
     68                 Edge e=edges[G[u][i]];
     69                 if(d[e.v]>d[u]+e.c){
     70                     d[e.v]=d[u]+e.c;
     71                     q.push((HeapNode){d[e.v],e.v});
     72                 }
     73             }
     74         }
     75     }
     76 };
     77 
     78 int grid[maxr][maxc][4];
     79 
     80 int n,id[maxr][maxc][4][2];
     81 
     82 int ID(int r,int c,int dir,int doubled)
     83 {
     84     int& x=id[r][c][dir][doubled];
     85     if(x==0)x=++n;
     86     return x;
     87 }
     88 
     89 int R,C;
     90 
     91 bool cango(int r,int c,int dir)
     92 {
     93     if(r<0||r>=R||c<0||c>=C)
     94         return false;
     95     return grid[r][c][dir]>0;
     96 }
     97 
     98 Dijkstra solver;
     99 
    100 int readint()
    101 {
    102     int x;
    103     scanf("%d",&x);
    104     return x;
    105 }
    106 
    107 int main()
    108 {
    109     int r1,c1,r2,c2,kase=0;
    110     while(scanf("%d%d%d%d%d%d",&R,&C,&r1,&c1,&r2,&c2)==6&&R)
    111     {
    112         r1--;c1--;r2--;c2--;
    113         memset(grid,0,sizeof(grid));
    114         for(int r=0;r<R;r++)//每次更新点(r,c)的下方和右方的边
    115         {
    116             for(int c=0;c<C-1;c++)
    117                 grid[r][c][RIGHT]=grid[r][c+1][LEFT]=readint();
    118             if(r!=R-1)
    119                 for(int c=0;c<C;c++)
    120                     grid[r][c][DOWN]=grid[r+1][c][UP]=readint();
    121         }
    122 
    123         solver.init(R*C*8+1);
    124 
    125         n=0;
    126         memset(id,0,sizeof(id));
    127 
    128         for(int dir=0;dir<4;dir++)//对起点做double
    129             if(cango(r1,c1,dir))
    130                 solver.add(0,ID(r1+dr[dir],c1+dc[dir],dir,1),grid[r1][c1][dir]*2);
    131 
    132         for(int r=0;r<R;r++)//要把所有点都处理完整,不能到r2,c2就结束
    133             for(int c=0;c<C;c++)
    134                 for(int dir=0;dir<4;dir++)
    135                     if(cango(r,c,inv[dir]))
    136                         //为什么是inv?grid[r][c][inv[dir]]是点(r,c)沿inv[dir]方向到点x的边权,同样也是点x->点(r,c)的边权:老边
    137                         //而区别在于判断进入(r,c)的边,与出(r,c)进(new,r,newc)的边方向是否一致
    138                         for(int newdir=0;newdir<4;newdir++)
    139                             if(cango(r,c,newdir))
    140                                 for(int doubled=0;doubled<2;doubled++){
    141                                     int newr=r+dr[newdir];
    142                                     int newc=c+dc[newdir];
    143                                     int v=grid[r][c][newdir],newdoubled=0;
    144                                     if(dir!=newdir){//若方向不一致,两条边都要加倍
    145                                         if(!doubled)//对于前一条边分两种情况讨论:已经double(之前已经加速或起步),未double
    146                                             v+=grid[r][c][inv[dir]];//
    147                                         newdoubled=1;
    148                                         v+=grid[r][c][newdir];
    149                                     }
    150                                     solver.add(ID(r,c,dir,doubled),ID(newr,newc,newdir,newdoubled),v);
    151                                     //若方向一致,连到newdouble==0的两条边权值相同
    152                                     //否则,连到newdouble==1的两条边相差grid[r][c][inv[dir]],即分开讨论老边是否已加倍,由于最后求最短路,不影响
    153                                 }
    154         solver.dijkstra(0);
    155 
    156         int ans=INF;
    157         for(int dir=0;dir<4;dir++)//从与终点(r2,c2)相连的八个状态中取最小值
    158             if(cango(r2,c2,inv[dir]))
    159                 for(int doubled=0;doubled<2;doubled++)
    160                 {
    161                     int v=solver.d[ID(r2,c2,dir,doubled)];
    162                     if(!doubled)
    163                         v+=grid[r2][c2][inv[dir]];
    164                     ans=min(ans,v);
    165                 }
    166 
    167         printf("Case %d: ",++kase);
    168         if(ans==INF)
    169             printf("Impossible
    ");
    170         else
    171             printf("%d
    ",ans);
    172     }
    173     return 0;
    174 }
    View Code

     后记:

      这里的数组id[][][][],以及函数 ID()的处理很值得学习一下。在处理多状态等复杂情况是很实用。

      用这个方法自己写了一道题,一遍就通过了样例,好有成就感,可惜uva在这道题上又挂了= =

  • 相关阅读:
    175. Combine Two Tables
    VirtualBox下安装CentOS7系统
    idea配置maven
    idea配置jdk
    SpringBoot在yml中添加自定义配置并识别
    多表联查另一个表的所有
    java后台判断字符串相等 equals
    查询字段内容截取
    idea刷新项目、清除项目缓存
    SpringBoot集成FreeMarker
  • 原文地址:https://www.cnblogs.com/zstu-abc/p/3278633.html
Copyright © 2020-2023  润新知