NOIP2013D2T3-华容道

问题描述

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间。
小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:
在一个 n × m 棋盘上有 n × m 个格子,其中有且只有一个格子是空白的,其余 n × m 1 个格子上每个格子上有一个棋子,每个棋子的大小都是 1 × 1 的;
有些棋子是固定的,有些棋子则是可以移动的;
任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。
游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。
给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的, 但是棋盘上空白的格子的初始位置、 指定的可移动的棋子的初始位置和目标位置却可能不同。第 ii 次玩的时候, 空白的格子在第 EXi行第 EYi列,指定的可移动棋子的初始位置为第 SXi行第 SYi列,目标位置为第 TXi行第 TYi列。
假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。
输入格式
第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示n,m,q ;
接下来的 nn 行描述一个 n × m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态, 0 表示该格子上的棋子是固定的, 1 表示该格子上的棋子可以移动或者该格子是空白的。
接下来的 q 行,每行包含 66 个整数依次是 E X i , E Y i , S X i , S Y i , T X i , T Y i E X ,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。
输出格式
共 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出 −1 。
样例输入

3 4 2
0 1 1 1
0 1 1 0
0 1 0 0
3 2 1 2 2 2
1 2 2 2 3 2

样例输出

2
-1

思路分析

不会,抄大佬博客
①灵活改变状态表示方法,整合无用状态,减少无用状态
②将状态抽离,构图,转化为图论问题
故:正确的步骤为
第一步,抽离有用状态
第二步,有用状态与有用的后继状态 连边构图,
边权为:由有用状态 到 后继状态 所需的最小步数
第三步,初始状态 到 目标状态 ,跑最短路(最好是跑spfa)
技巧:
我们可以用0,1,2,3分别表示空白格在指定格的上右下左
= 1 + 1 4 + 0 / 1 / 2 / 3 i n t n u m b e r s ( i n t i , i n t j ) r e t u r n ( i 1 ) m + j 1 << 2 ;
其实所有网格图中的状态都可以采取类似的方法
状态编号= 图中编号* S+ x ,x∈[0,S) S=每种编号状态数
所以在定义dx数组跟dy数组的时候一定要一一对应!!!
坑点:
①如上技巧所述:
在定义dx数组跟dy数组的时候一定要一一对应!!!不然很吃亏…
②写n,m千万不要写反了…写反了很尴尬,读不进去…虽然是可以检查出来,不过这个真的很致命!!!!
③在进行连边的时候,其实还有第四种后继状态:
就是空白格与指定格的位置互换
我使用的是上右下左这样的dx,dy,所以第四种状态的转换就简单的变为{空白格的numbers+(d+2)%4} ps:d是枚举的初始状态空白格相对于指定格的方向。
除此之外的状态用指定格的numbers+d即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define INF 0x7fffffff
using namespace std;

const int Maxt = 32;
const int Maxn = 3610;
const int Maxm = Maxn * 5;
int n,m,p;
bool a[Maxt][Maxt],vis[Maxn];
int dx[4] = {-1,0,1, 0},
    dy[4] = { 0,1,0,-1};
int predis[Maxt][Maxt],dis[Maxn];

struct game {
    int next,to,w;
}e[Maxm];
int top,head[Maxn];
void add(int u,int v,int val) {
    top++;
    e[top].to=v;
    e[top].w=val;
    e[top].next=head[u];
    head[u]=top;
}

struct start {
    int x,y;
} nxt,cur;
queue<start>q;
queue<int>que;

int numbers(int i,int j) {
    j--; 
    return (i-1)*m+j<<2;
}

void bfs(int ex,int ey,int px,int py,int d) {
    int cx,cy,nx,ny; 
    memset(predis,-1,sizeof(predis));
    predis[px][py]=1;
    predis[ex][ey]=0;
    cur.x=ex,cur.y=ey;
    q.push(cur);
    while(!q.empty()) {
        cur=q.front();
        q.pop();
        cx=cur.x,cy=cur.y;
        for(int i=0; i<4; ++i) {
            nx=cur.x+dx[i],ny=cur.y+dy[i];
            if(a[nx][ny] && predis[nx][ny]==-1) {
                predis[nx][ny]=predis[cx][cy]+1;
                nxt.x=nx,nxt.y=ny;
                q.push(nxt);
            }
        }
    }
    if(d==8) return;
    int tmp=numbers(px,py);
    for(int i=0; i<4; ++i) {
        int x=px+dx[i],y=py+dy[i];
        if(predis[x][y]>0)
            add(tmp+d,tmp+i,predis[x][y]);
    }
    add(tmp+d,numbers(ex,ey)+(d+2)%4,1);
}

void spfa(int sx,int sy) {
    int tmp;
    memset(dis,-1,sizeof(dis));
    for(int i=0; i<4; ++i) {
        int x=sx+dx[i],y=sy+dy[i];
        if(predis[x][y]!=-1) {
            tmp=numbers(sx,sy)+i;
            dis[tmp]=predis[x][y];
            que.push(tmp);
        }
    }
    int u;
    while(!que.empty()) {
        u=que.front();
        que.pop();
        vis[u]=false;
        for(int i=head[u]; i; i=e[i].next) {
            int v=e[i].to;
            if(dis[v]==-1 || dis[v]>dis[u]+e[i].w) {
                dis[v]=dis[u]+e[i].w;
                if(!vis[v]) {
                    vis[v]=true;
                    que.push(v);
                }
            }
        }
    }
} 

int main() {
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=m; ++j)
            scanf("%d",&a[i][j]);
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=m; ++j)
            if(a[i][j]) {
                if(a[i-1][j]) bfs(i-1,j,i,j,0); 
                if(a[i][j+1]) bfs(i,j+1,i,j,1);
                if(a[i+1][j]) bfs(i+1,j,i,j,2);
                if(a[i][j-1]) bfs(i,j-1,i,j,3);
            }
    int ex,ey,sx,sy,tx,ty,ans;
    while(p--) {
        scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
        if(sx==tx && sy==ty) {
            printf("0\n");
            continue;
        }
        bfs(ex,ey,sx,sy,8);
        spfa(sx,sy);
        ans=INF;
        int tmp=numbers(tx,ty);
        for(int i=0; i<4; ++i)
            if(dis[tmp+i]!=-1) 
                ans=min(ans,dis[tmp+i]);
        if(ans==INF)
            ans=-1;
        printf("%d\n",ans); 
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Liukairui/article/details/81285129