Steam Roller UVALive - 4128

Steam Roller UVALive - 4128

图论·最短路

题目大意:

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

题解:

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

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

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

Code:

#include 
#include 
#include 
#include 
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 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;jscanf("%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;j1;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);
    }
}

你可能感兴趣的:(<,图论,>,最短路)