noip2013day2-华容道

题目描述

\(B\) 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用 编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多 少时间。

\(B\) 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

  1. 在一个 \(n*m\) 棋盘上有 \(n*m\) 个格子,其中有且只有一个格子是空白的,其余 \(n*m-1\)个格子上每个格子上有一个棋子,每个棋子的大小都是 $1*1 $的;

  2. 有些棋子是固定的,有些棋子则是可以移动的;

  3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 \(q\) 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘 上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第$ i$ 次 玩的时候,空白的格子在第$ EX_i$ 行第 \(EY_i\) 列,指定的可移动棋子的初始位置为第 \(SX_i\) 行第 \(SY_i\) 列,目标位置为第 \(TX_i\) 行第 \(TY_i\) 列。

假设小 \(B\) 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请 你告诉小 \(B\) 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

Input

第一行有 \(3\) 个整数,每两个整数之间用一个空格隔开,依次表示 \(n、m\) 和$ q$;

接下来的$ n$ 行描述一个 \(n*m\) 的棋盘,每行有 \(m\) 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,\(0\) 表示该格子上的棋子是固定的,\(1\) 表示该格子 上的棋子可以移动或者该格子是空白的。

接下来的 \(q\) 行,每行包含 \(6\) 个整数依次是 \(EX_i、EY_i、SX_i、SY_i、TX_i、TY_i\),每两个整 数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

\(100\%\)的数据,\(1 ≤ n, m ≤ 30,q ≤ 500。\)

Output

输出有 \(q\) 行,每行包含$ 1 \(个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出\)−1$

Sample Input

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

Sample Output

2
-1

很显然,看到这道题的第一眼就想到了广搜。

每次,只用记录空白块以及指定块的位置,直接广搜。

然而,我们仔细算一下时间复杂度\(O(q*(n*m)^2)\)

不能愉快的过掉此题。。。。

考虑优化,我们发现:

1.指定块能移动到指定位置当且仅当空白块在指定块边上。

2.当指定块移动时,必定是空白块到了指定块的另一边,在进行交换。

并且,这些状态的转移步数在指定块固定时可以直接广搜得到。

于是我们考虑,对那些状态进行建图,建完图后进行连边。

那么如何对这些状态进行建图呢?

之前,我们发现只有空白块在指定块的四周才有用,只有这才是有效状态。

所以,我们定义一个有效状态为:

空白块在指定块的上下左右

于是,我们就可以很方便的对一个状态进行哈希,一个状态的哈希函数为:

inline int Id(int x,int y,int cnt){
    return 120*x+4*y+cnt;//x,y为指定块的所在的位置,cnt为空白块在指定块的上下左右的位置
}

定义出了哈希函数后,我们可以对两个状态进行连边,很显然,对于一个有效状态,其后续状态有四个:

为空白块在其他的三个方向,以及空白块和指定块交换(这个状态的边权是一)

于是,我们对每个状态进行广搜建图,连边。

最后,对于每个询问直接在建好的图上跑最短路即可。

代码如下

#include <bits/stdc++.h>
 
using namespace std;
 
#define LL long long
#define u64 unsigned long long
#define u32 unsigned int
#define reg register
#define Raed Read
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
 
inline int Read() {
    int res = 0, f = 1;
    char c;
    while (c = getchar(), c < 48 || c > 57)if (c == '-')f = 0;
    do res = (res << 3) + (res << 1) + (c ^ 48);
    while (c = getchar(), c >= 48 && c <= 57);
    return f ? res : -res;
}
 
template<class T>inline bool Min(T &a, T const&b) {
    return a > b ? a = b, 1 : 0;
}
template<class T>inline bool Max(T &a, T const&b) {
    return a < b ? a = b, 1 : 0;
}
 
const int N=35,M=4505;
const int dx[4]= {1,-1,0,0},dy[4]= {0,0,1,-1};
 
bool MOP1;
 
int n,m,q,A[N][N];
 
struct Link_list {
    int Tot,Head[M],cost[M<<1],to[M<<1],Nxt[M<<1];
    inline void clear(void) {
        Tot=0;
        memset(Head,0,sizeof Head);
    }
    inline void AddEdge(int a,int b,int c) {
        to[++Tot]=b,cost[Tot]=c,Nxt[Tot]=Head[a],Head[a]=Tot;
    }
} G;
 
inline int Id(int x,int y,int cnt) {
    return 120*x+4*y+cnt;
}
 
struct T3Ac {
    struct node {
        int x,y;
    } Q[N*N*N*N];
    int dis[N][N];
    void bfs(int x1,int y1,int x2,int y2,int cnt) {
        memset(dis,0,sizeof dis);
        dis[x1][y1]=1;
        int L=0,R=0;
        Q[++R]=(node)<%x1,y1%>;
        while(L<R) {
            node Now=Q[++L];
            rep(i,0,3) {
                int Dx=dx[i]+Now.x,Dy=dy[i]+Now.y;
                if(Dx<1||Dy<1||Dx>n||Dy>m)continue;
                if(Dx==x2&&Dy==y2)continue;
                if(!A[Dx][Dy])continue;
                if(dis[Dx][Dy])continue;
                dis[Dx][Dy]=dis[Now.x][Now.y]+1;
                Q[++R]=(node)<%Dx,Dy%>;
            }
        }
        if(!(cnt^4))return;
        rep(i,0,3) {
            int Dx=dx[i]+x2,Dy=dy[i]+y2;
            if(Dx<1||Dy<1||Dx>n||Dy>m)continue;
            if(Dx==x1&&Dy==y1)continue;
            if(!dis[Dx][Dy])continue;
            G.AddEdge(Id(x2,y2,cnt),Id(x2,y2,i),dis[Dx][Dy]-1);
        }
        G.AddEdge(Id(x2,y2,cnt),Id(x1,y1,cnt^1),1);
    }
    int vis[M],D[M],q1[N*N*N*N];
    void spfa(int x1,int y1) {
        int L=0,R=0;
        memset(D,63,sizeof D);
        memset(vis,0,sizeof vis);
        rep(i,0,3) {
            int Dx=dx[i]+x1,Dy=dy[i]+y1;
            if(Dx<1||Dy<1||Dx>n||Dy>m)continue;
            if(!dis[Dx][Dy])continue;
            D[Id(x1,y1,i)]=dis[Dx][Dy]-1,vis[Id(x1,y1,i)]=1;
            q1[++R]=Id(x1,y1,i);
        }
        while(L<R) {
            int x=q1[++L];
            vis[x]=0;
            erep(i,G,x) {
                int y=G.to[i],z=G.cost[i];
                if(D[y]>D[x]+z) {
                    D[y]=D[x]+z;
                    if(!vis[y])vis[y]=1,q1[++R]=y;
                }
            }
        }
    }
    inline void solve(void) {
        rep(i,1,n)rep(j,1,m)A[i][j]=Read();
        rep(i,1,n)rep(j,1,m) {
            if(!A[i][j])continue;
            rep(k,0,3) {
                int Dx=dx[k]+i,Dy=dy[k]+j;
                if(A[Dx][Dy])bfs(Dx,Dy,i,j,k);
            }
        }
        rep(i,1,q) {
            int ex=Read(),ey=Read(),sx=Read(),sy=Read(),tx=Read(),ty=Read();
            if(sx==tx&&sy==ty) {
                puts("0");
                continue;
            }
            bfs(ex,ey,sx,sy,4);
            spfa(sx,sy);
            int Ans=1e9;
            rep(j,0,3)Min(Ans,D[Id(tx,ty,j)]);
            if(Ans<1e9)printf("%d\n",Ans);
            else puts("-1");
        }
    }
} P100;
 
bool MOP2;
 
inline void _main(void) {
    n=Read(),m=Read(),q=Read();
    P100.solve();
}
 
signed main() {
#define offline1
#ifdef offline
    freopen("puzzle.in", "r", stdin);
    freopen("puzzle.out", "w", stdout);
    _main();
    fclose(stdin);
    fclose(stdout);
#else
    _main();
#endif
    return 0;
}
posted @ 2019-08-12 21:04  dsjkafdsaf  阅读(177)  评论(0编辑  收藏  举报