Steam Roller UVALive

来源:互联网 发布:网络光纤收发器 编辑:程序博客网 时间:2024/05/03 04:01

Steam Roller UVALive - 4128

图论·最短路

题目大意:

给你一张格子图,r根横线,c根竖线。告诉你起点和终点,然后从起点走,每条边有权值,如果是0,就表示无法通行。走的规则是(通俗点):车子的惯性比较大,如果你在下个路口要转弯,那么后半段就开慢了,好转弯,转弯完了之后,你要加速,那么前半段就慢了,这两种情况都会使这段路的时间加倍,但是如果一条路同时是这样,那么也只算两倍。起点这终点一个启动,一个是制动,那么和他们相连的第一条边也算两倍。问你最短时间,如果不行,就输出 “Impossible” 。

题解:

设计状态:节点(x,y,lastdir,doubled)表示在点(x,y),上一次走的方向是lastdir,以及刚刚走过来的这条边有没有加倍。
然后按照题意连边,具体请参见代码。

但是注意:这里有坑,就是到达终点的时候,由于边权加倍规则的存在,那么到达终点了可以再往前走一段,再回来,也就是说,本来不是说到达终点的边也要加倍,但是并不是在更新的时候直接判断加倍,这样会有问题,我的处理方式是,终点和其他点的处理方式一样,从队列里拿粗来的时候,判断是不是终点,然后再看 doubled ,就是到达终点的这条边正常模式下有没有加倍,如果没有就加倍,然后更新 ans。

蒙蒙一开始自己写了一份建好图然后跑spfa的,没调过。
代码能力太弱。。。
然后抄了一份神题解,在dij的时候再处理边连向哪里和边权,感觉很简洁。
而且大神直接把上一条边的边权和这个点的d[]存在Node里面,不是像蒙蒙那样每次用奇奇怪怪的函数去找(我是zz不要管我)。

Code:

#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;const int N = 105;const int INF = 0x3f3f3f3f;int n,m,sx,sy,tx,ty;struct Edge{    int x1,y1,x2,y2;    int val,dir; int next;}e[N*N*4];int head[N][N]; int ec;void clear(){ memset(head,0,sizeof(head)); ec=0; }void add(int x1,int y1,int x2,int y2,int val,int dir){    ec++;    e[ec].x1=x1, e[ec].y1=y1;    e[ec].x2=x2, e[ec].y2=y2;    e[ec].val=val; e[ec].dir=dir;    e[ec].next=head[x1][y1]; head[x1][y1]=ec;}struct Node{    int x,y,val;    int lastdir,lastval,doubled;    Node(int a,int b,int v,int ld,int lv,int bo){        x=a; y=b; val=v; lastdir=ld; lastval=lv; doubled=bo;    }    bool operator < (const Node &tp) const {        return val > tp.val;    }};int done[N][N][5][3];int d[N][N][5][3];int ans;void dij(){    priority_queue<Node> q;    memset(done,0,sizeof(done));    memset(d,0x3f,sizeof(d));    d[sx][sy][4][1]=0;    q.push(Node(sx,sy,0,4,0,1));    while(!q.empty()){        Node u=q.top(); q.pop();        if(u.x==tx && u.y==ty){            int tp=u.val;            if(!u.doubled){                tp+=u.lastval;            }            ans=min(ans,tp);        }        if(done[u.x][u.y][u.lastdir][u.doubled]) continue;        done[u.x][u.y][u.lastdir][u.doubled]=1;        for(int i=head[u.x][u.y];i;i=e[i].next){            int xx=e[i].x2;            int yy=e[i].y2;            int val=e[i].val;            int dir=e[i].dir;            int oldcnt=0;            if(dir!=u.lastdir && u.doubled==0) oldcnt=1;            int newcnt=1,nextdoubled=0;            if(dir!=u.lastdir){ newcnt=2; nextdoubled=1; }            int tp=d[u.x][u.y][u.lastdir][u.doubled]+newcnt*val+oldcnt*u.lastval;            if(d[xx][yy][dir][nextdoubled]>tp){                d[xx][yy][dir][nextdoubled]=tp;                q.push(Node(xx,yy,tp,dir,val,nextdoubled));            }        }    }}int main(){    freopen("a.in","r",stdin);    int cas=0;    while(~scanf("%d%d%d%d%d%d",&n,&m,&sx,&sy,&tx,&ty)){        if(n+m==0) break;        sx--; sy--; tx--; ty--;        clear();        for(int i=0;i<2*n-1;i++){            int val;            if(i&1){                for(int j=0;j<m;j++){                    scanf("%d",&val);                    if(val==0) continue;                    add(i/2+1,j,i/2,j,val,3);                    add(i/2,j,i/2+1,j,val,1);                }            }            else{                for(int j=0;j<m-1;j++){                    scanf("%d",&val);                    if(val==0) continue;                    add(i/2,j,i/2,j+1,val,0);                    add(i/2,j+1,i/2,j,val,2);                }            }        }        ans=INF;        dij();        printf("Case %d: ",++cas);        if(ans>=INF) puts("Impossible");        else printf("%d\n",ans);    }}
原创粉丝点击