【最短路】LA4128 压路机

来源:互联网 发布:photoshop cc2015 mac 编辑:程序博客网 时间:2024/04/28 09:36

压路机
【问题描述】
Johnny 开着一辆蒸汽压路机(拖拉机?),像其他的蒸汽压路机一样,它很
慢,而且要花更多的时间启动,改变方向,或是停下。Johnny 刚刚完成了一天
的工作并正在开着他的蒸汽压路机回家去见他妻子。你的任务是找到对他和他的
蒸汽压路机而言的最短路。
Johnny 所住的城市是规则结构的(街道形成了正交系统)。城市街道编排在
一个矩网格的节点间。每个节点和它的邻居(最多四个)由街道相连。每个街道
恰好1 单位长。当Johnny 进入一个街道,他必须到达另一端,从那里,他可以
选择向四个方向行进到下一个节点,依次类推。
在研究了街道的路况之后,Johnny 计算了走过每一条街道的用时。这个时
间对两个方向来说是相同的。然而,Johnny 的计算只满足最理想的状态——即
蒸汽压路机在进入这条街道时已经进入状态而且不需要加速或刹车。只要蒸汽压
路机在经过某条街道之前或之后立即改变方向,它经过这条街道的实际耗时会变
为估计值的2 倍。这种情况对于压路机从某个节点发动(比如Johnny 的起点)
和到某个节点刹车(比如Johnny 的终点)也适用。
下面的图片是一个例子。数字说明了穿过对应街道的“理想”时间。没有表
明数字的街道不允许压路机穿过。Johnny 想要从左上角到右下角。
全部是9 的那条路看起来更加快捷。然而,因为加速和刹车的限制,每一条
边都需要2 倍的时间,这使得总时间达到108。由10 组成的路径更快,因为Johnny
可以在其中的两条路径上全速通过,即总用时100。
【输入文件】
输入文件为roller.in。
第一行为六个正整数开头:R C r1 c1 r2 c2。R 和C 描述了城市的大小,r1
和c1 给出了起点坐标,r2 和c2 给出了Johnny 的家的位置。这两个坐标必定不
第6页共6页
同。
下一行,有C-1 个非负整数用来描述(1,1)到(1,2),(1,2)到(1,3),(1,3)到
(1,4)……的期望耗时。再下一行,有C 个非负整数描述(1,1)到(2,1),(1,2)到
(2,2)……的期望耗时。在下一行,又是C-1 个数描述下一行的期望耗时。输入一
直这样延续直到描述全部街道。这些整数都表示的是不加速、刹车、转向时的耗
时。如果这些特殊情况中的一种或多种发生,那么时间翻倍。这些整数中可能会
有0,表示这条路不能经过。
【输出文件】
输出文件为roller.out。
输出一个整数,即最短总耗时。如果不能到达,输出Impossible。
【输入样例】
4 4 1 1 4 4
10 10 10
9 0 0 10
0 0 0
9 0 0 10
9 0 0
0 9 0 10
0 9 9
【输出样例】
100
【数据规模和约定】
对于50%的数据,R,C≤20。
对于100%的数据,输入中所有数不会超过100。

Solution:
看见这道题的第一反应当然就是求起点到终点的最短路。可是中间由于转弯这个特殊的性质,在求最短路的过程中有一些特殊的地方需要注意.
考虑每个点有8个状态:
F[i][j][dir][doubled]
i,j表示点的坐标。
dir表示走到这个点的朝向。
然后doubled表示 走到这个点是否转弯。
很明显前面三个i,j,dir很容易想到。
可是为什么要用doubled这一变量呢
给出如下的例子
这里写图片描述

考虑从上面的节点转移到中间的节点。
①如果上面的节点从边“2” 转移过来。则更新的边“4”不用翻倍。
②如果上面的节点从边“3”或者“1”转移过来 毫无疑问,如果只考虑当前新加入的边”4” “4”号边会翻倍。
值得注意的是,思考的时候我们只考虑从一个点更新另一个点的情况。而不用考虑其他点怎么得到。

得到最短路的转移方程。

if(k1!=k2){                    int update=min(f[y][x][k1][0],f[y][x][k1][1])+len*2;                    if(f[vy][vx][k2][1]>update){                        f[vy][vx][k2][1]=update;                    }                }                else{                    int update=min(f[y][x][k1][0]+len,f[y][x][k1][1]+len*2);                    if(f[vy][vx][k1][0]>update){                        f[vy][vx][k1][0]=update;                    }                }   `这里写代码片`利用SPFA的过程不断更新即可。```using namespace std;int dx[5]={0,1,-1,0,0};int dy[5]={0,0,0,1,-1};int f[101][101][5][2];int exist[101][101];int sta_x,sta_y,end_x,end_y;struct Point{    int x,y; }rec[100001];int m,n,hen[M][M],shu[M][M],ans;queue < int > q;void Init(){    for (int i=1;i<=2*n-1;i++){        if(i%2==1)            for (int j=1;j<=m-1;j++)                scanf("%d",&hen[i/2+1][j]);        if(i%2==0)            for (int j=1;j<=m;j++)                  scanf("%d",&shu[j][i/2]);    }}int Query(int a,int b,int c,int d){     //方便查找两个相邻点的距离     if(a==c)        if(d==b+1) return hen[a][b];        if(b==d+1) return hen[a][d];    if(b==d)        if(c==a+1) return shu[b][a];        if(a==c+1) return shu[b][c];}void test(){    while(true){        int a,b,c,d;        cin>>a>>b>>c>>d;        cout<<Query(a,b,c,d)<<endl;    }}void spfa(){    int cnt=0;    q.push(++cnt);    rec[cnt].x=sta_x;rec[cnt].y=sta_y;    exist[sta_y][sta_x]=true;    memset(f,10001,sizeof(f));    f[sta_y][sta_x][1][1]=0;    f[sta_y][sta_x][2][1]=0;    f[sta_y][sta_x][3][1]=0;    f[sta_y][sta_x][4][1]=0;    while(!q.empty()){        int cmt=q.front();q.pop();        int x=rec[cmt].x;int y=rec[cmt].y;        exist[y][x]=false;        for (int k1=1;k1<=4;k1++){            int vx=x+dx[k1];            int vy=y+dy[k1];            if(vx<=0||vx>m||vy<=0||vy>n)                continue;            int flag=0;            int len=Query(y,x,vy,vx);            if(len==0) continue;            for (int k2=1;k2<=4;k2++){                int sy=vy+dy[k2],sx=vx+dx[k2];                if(sx<=0||sx>m||sy<=0||sy>n) continue;                if(k1!=k2){                    int update=min(f[y][x][k1][0],f[y][x][k1][1])+len*2;                    if(f[vy][vx][k2][1]>update){                        f[vy][vx][k2][1]=update;                    }                }                else{                    int update=min(f[y][x][k1][0]+len,f[y][x][k1][1]+len*2);                    if(f[vy][vx][k1][0]>update){                        f[vy][vx][k1][0]=update;                    }                }               }        }    }}int main(){    freopen("roller.in","r",stdin);        //freopen("roller.out","w",stdout);     scanf("%d %d",&n,&m);        scanf("%d %d %d %d",&sta_y,&sta_x,&end_y,&end_x);    Init();    #define INF (1000000007)    ans=INF;    //test();    //cout<<Query(1,4,2,4)<<endl;    spfa();    for (int i=1;i<=4;i++)        ans=min(ans,f[end_y][end_x][i][1]);    if(ans==INF) cout<<"Impossible";    else printf("%d",ans);    return 0;}
0 0
原创粉丝点击