(noip 2013 華容道)

傳送門


Solution

70分做法:

  • vis[x][y][kx][ky] 表示指定旗子在(x,y) ,空白格在(kx,ky) 的狀態
  • 廣搜就是移動空白格
  • 當空白格移動到指定旗子的位置時,交換位置
  • 隊列中每個裝態對應的步數是單調不降的,因此第一次走到目標位置就是最小步數

Code

// by spli
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;

int n,m,Q;
bool can[35][35];
int ex,ey,sx,sy,tx,ty;
int mx[5]={0,1,0,-1,0};
int my[5]={0,0,1,0,-1};
bool vis[35][35][35][35];
struct node{
    int x,y,kx,ky,cnt;
};
queue<node>q;

bool bfs(){
    while(!q.empty()) q.pop();
    vis[sx][sy][ex][ey]=1;
    q.push((node){sx,sy,ex,ey,0});
    int x,y,kx,ky;
    while(!q.empty()){
        node f=q.front();
        q.pop();
        for(int i=1;i<=4;++i){
            x=f.x;y=f.y;
            kx=f.kx+mx[i];
            ky=f.ky+my[i];
            if(kx==x&&ky==y) x=f.kx,y=f.ky;
            if(!vis[x][y][kx][ky]&&x<=n&&x>=1&&y<=m&&y>=1&&can[x][y]&&can[kx][ky]){
                vis[x][y][kx][ky]=1;
                if(x==tx&&y==ty){
                    printf("%d\n",f.cnt+1);
                    return 1;
                }
                q.push((node){x,y,kx,ky,f.cnt+1});
            }
        }
    }
    return 0;
}

int main(){
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            scanf("%d",&can[i][j]);
    while(Q--){
        scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
        memset(vis,0,sizeof(vis));
        if(sx==tx&&sy==ty){
            puts("0");
            continue;
        }
        if(bfs()) continue;
        else puts("-1");
    }
    return 0;
}

滿分做法:

  • 把廣搜的過程分成兩個部分:①空白格移動到指定旗子的上下左右+②指定旗子移動到目標位置
  • ①過程bfs解決
  • ②:當指定旗子要從(x,y) 移動到(x+1,y) 時,需要空白格先移動到(x+1,y) ,又因爲此時空白格一定在(x,y) 上下左右的某個位置,而多次詢問中,空白格從某個點上下左右不經過這個點的情況下到達這個點上下左右其它位置的步數是固定的,同樣可以bfs預處理
  • 因此②可以跑spfa,轉移的代價就是預處理的步數

Code

// by spli
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;

const int inf=0x3f3f3f3f;
int n,m,Q;
bool can[35][35];
int ex,ey,sx,sy,tx,ty;
int mx[5]={0,1,0,-1};
int my[5]={1,0,-1,0};
int mv[35][35][5][5];
int dis[35][35],d[35][35][5];
bool vis[35][35][5];
struct node{
    int x,y,z;
};
queue<node>s,q;

bool check(int x,int y){
    if(x<1||x>n||y<1||y>m||!can[x][y]) return 0;
    return 1;
}

void bfs(int x,int y){
    while(!s.empty()) s.pop();
    while(!q.empty()) q.pop();
    int kx,ky,px,py;
    node f;
    for(int i=0;i<4;++i){
        kx=x+mx[i];
        ky=y+my[i];
        if(check(kx,ky)) s.push((node){kx,ky,i});
    }
    while(!s.empty()){
        memset(dis,0x3f3f3f3f,sizeof(dis));
        f=s.front();
        s.pop();
        while(!q.empty()) q.pop();
        q.push((node){f.x,f.y,f.z});
        dis[f.x][f.y]=0;
        int z=f.z;
        while(!q.empty()){
            node f=q.front();
            q.pop();
            px=f.x;py=f.y;
            for(int i=0;i<4;++i){
                kx=px+mx[i];
                ky=py+my[i];
                if(check(kx,ky)&&dis[kx][ky]==inf&&(kx!=x||ky!=y)){
                    dis[kx][ky]=dis[px][py]+1;
                    q.push((node){kx,ky,i});
                }
            }
        }
        for(int i=0;i<4;++i){
            kx=x+mx[i];
            ky=y+my[i];
            if(check(kx,ky))
                mv[x][y][z][i]=dis[kx][ky];
        }
    }
}

void pre(){
    memset(dis,0x3f3f3f3f,sizeof(dis));
    dis[ex][ey]=0;
    while(!q.empty()) q.pop();
    q.push((node){ex,ey,0});
    node f;
    int kx,ky,px,py;
    while(!q.empty()){
        f=q.front();
        q.pop();
        px=f.x;py=f.y;
        for(int i=0;i<4;++i){
            kx=px+mx[i];
            ky=py+my[i];
            if(check(kx,ky)&&(kx!=sx||ky!=sy)&&dis[kx][ky]==inf){
                dis[kx][ky]=dis[px][py]+1;
                q.push((node){kx,ky,0});
            }
        }
    }
}

void spfa(){
    if(sx==tx&&sy==ty){
        puts("0");
        return;
    }
    node f;
    int kx,ky,px,py,z;
    memset(d,0x3f3f3f3f,sizeof(d));
    memset(vis,0,sizeof(vis));
    while(!q.empty()) q.pop();
    for(int i=0;i<4;++i){
        kx=sx+mx[i];
        ky=sy+my[i];
        if(check(kx,ky)&&dis[kx][ky]<inf){
            q.push((node){sx,sy,i});
            d[sx][sy][i]=dis[kx][ky];
            vis[sx][sy][i]=1;
        }
    }
    while(!q.empty()){
        f=q.front();
        q.pop();
        px=f.x;py=f.y;z=f.z;
        vis[px][py][z]=0;
        kx=px+mx[z];
        ky=py+my[z];
        if(d[kx][ky][(z+2)%4]>d[px][py][z]+1){
            d[kx][ky][(z+2)%4]=d[px][py][z]+1;
            if(!vis[kx][ky][(z+2)%4]){
                vis[kx][ky][(z+2)%4]=1;
                q.push((node){kx,ky,(z+2)%4});
            }
        }
        for(int i=0;i<4;++i){
            kx=px+mx[i];
            ky=py+my[i];
            if(check(kx,ky)&&i!=z&&d[px][py][i]>d[px][py][z]+mv[px][py][z][i]){
                d[px][py][i]=d[px][py][z]+mv[px][py][z][i];
                if(!vis[px][py][i]){
                    vis[px][py][i]=1;
                    q.push((node){px,py,i});
                }
            }
        }
    }
    int ans=inf;
    for(int i=0;i<4;++i)
        ans=min(ans,d[tx][ty][i]);
    if(ans>=inf) puts("-1");
    else printf("%d\n",ans);
}

int main(){
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) scanf("%d",&can[i][j]);
    memset(mv,0x3f3f3f3f,sizeof(mv));
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            if(can[i][j]) bfs(i,j);
    while(Q--){
        scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
        pre();
        spfa();
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章