图论·最短路
给你一张格子图,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);
}
}