模拟赛20181015 Uva1078 bfs+四维dp

题意:一张网格图,多组数据,输入n,m,sx,sy,tx,ty大小,起终点

接下来共有2n-1行,奇数行有m-1个数,表示横向的边权,偶数行有m个数,表示纵向的边权

样例输入:

4  4  1  1  4  4

10 10 10 

9 0 0 10

0 0 0

9 0 0 10

0 9 0 10

0 9 9

2 2 1 1 2 2

0

1 1

0

0 0 0 0 0 0

样例输出:

Case 1:  100

Case 2:  Impossible

我们发现此题的特点在于允许转向,也就是说我们可以将转向的状态利用一维表示出来以进行转移

同时由于起终点也需要*2,我们干脆新开两维,一维表示是否*2,另一维表示当前已经操作后面对的方向

利用spfa进行转移即可

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std;
const int NN=20000;
const int NNN=80000;
const int inf=100000000;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}

int g[NN][4];
int d[NNN];
bool vis[NNN];

int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};

int n,m,sx,sy,tx,ty,x,y,t,idx,w;
struct node{int x,y,t;};queue<node> q;

inline int calc(int x,int y){return (x-1)*m+(y-1);}
inline int calc(int x,int y,int t){return calc(x,y)*5+t;}
bool check(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=m;}

int main(){
    while(scanf("%d%d%d%d%d%d",&n,&m,&sx,&sy,&tx,&ty)!=EOF&&n&&m){
        
        rep(i,1,2*n-1)
        if(i&1) rep(y,1,m-1){
            x=(i+1)/2,w=read();if(!w) w=inf;
            g[calc(x,y)][0]=g[calc(x,y+1)][1]=w;}
        else rep(y,1,m){
            x=i/2,w=read();if(!w) w=inf;
            g[calc(x,y)][2]=g[calc(x+1,y)][3]=w;}
        //t代表的状态是身后已经加的边的状态 
        
        memset(d,60,sizeof d);
        d[calc(sx,sy,4)]=0;
        vis[calc(sx,sy,4)]=1;
        q.push((node){sx,sy,4});
        
        while(!q.empty()){
            x=q.front().x;
            y=q.front().y;
            t=q.front().t;q.pop();
            vis[calc(x,y,t)]=0;
            
            // 4 前后都要二倍 
            if(t<4){// i-i
                int xx=x+dx[t],yy=y+dy[t];
                if(!check(xx,yy)) continue;
                int w=g[calc(x,y)][t];
                if(d[calc(xx,yy,t)]>d[calc(x,y,t)]+w){
                    d[calc(xx,yy,t)]=d[calc(x,y,t)]+w;
                    if(!vis[calc(xx,yy,t)])
                    vis[calc(xx,yy,t)]=1,q.push((node){xx,yy,t});}
                w=w*2;//i-4
                if(d[calc(xx,yy,4)]>d[calc(x,y,t)]+w){
                    d[calc(xx,yy,4)]=d[calc(x,y,t)]+w;
                    if(!vis[calc(xx,yy,4)]) 
                    vis[calc(xx,yy,4)]=1,q.push((node){xx,yy,4});}
            }else{
                for(int i=0;i<=3;i++){
                    int xx=x+dx[i],yy=y+dy[i];
                    if(!check(xx,yy)) continue; 
                    int w=g[calc(x,y)][i]*2; //4 是转向所以w跟随i变化 
                    // 4-i 
                    if(d[calc(xx,yy,i)]>d[calc(x,y,t)]+w){
                        d[calc(xx,yy,i)]=d[calc(x,y,t)]+w;
                        if(!vis[calc(xx,yy,i)])
                        vis[calc(xx,yy,i)]=1,q.push((node){xx,yy,i});}
                    // 4-4 
                    if(d[calc(xx,yy,4)]>d[calc(x,y,t)]+w){
                        d[calc(xx,yy,4)]=d[calc(x,y,t)]+w;
                        if(!vis[calc(xx,yy,4)])
                        vis[calc(xx,yy,4)]=1,q.push((node){xx,yy,4});
                    }
                }
            }/* 
             i-i 正常直走 
             i-4 决策 转弯的第一条边   
                      到达终点 
             4-i 决策 转弯的第二条边  
                      起点结束 
             4-4 决策 转弯到终点
                 决策 连续转弯 
            */ 
        }// 三维状态 二维权值 
        int ans=d[calc(tx,ty,4)];
        if(ans>=inf) printf("Case %d: Impossible\n",++idx);
        else printf("Case %d: %d\n",++idx,ans);
    }return 0;
}

完结撒花

posted @ 2018-10-16 21:19  ASDIC减除  阅读(124)  评论(0编辑  收藏  举报