[noip2013]华容道

小 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 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

题解:

bfs,O(n^4)是比较容易看出来的60分做法(考试推荐),单组数据可过,由于多组数据q到达了500,所以40%会T;

那么从bfs的思路入手,可以发现bfs实际上在每次指定的格子移动一步时,都有大量的无用状态,而同时,图中的每个点在空格位置确定时,想移动一步的步数是一定的,那么可以考虑一个n^4的预处理,把每次这个格子要转移时花费的步数记录下来,就可以实现优化;

实现比较繁琐,见代码;

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iomanip>
#include<map>
#include<set>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long 
using namespace std;
#define LL long long 
#define up(i,j,n) for(int i=(j);(i)<=(n);(i)++)
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
#define FILE "Puzzle"
const int maxn=50,inf=100000000;
int read(){
    int x=0;bool flag=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')flag=1;ch=getchar();}
    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
    return flag?-x:x;
}
struct N{
    int y,next,v;
}e[500000];
int linkk[200000],len=0;
void insert(int x,int y,int v){
    e[++len].y=y;
    e[len].next=linkk[x];
    linkk[x]=len;
    e[len].v=v;
}
int n,m,Q;
int a[maxn][maxn];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
int f[maxn][maxn][4][4];
int d[maxn][maxn];
int V,A[maxn][maxn][4];
struct node{
    int bx,by;
}q[2000000];
int head=0,tail=0;
int bfs(int sx,int sy,int ex,int ey){
    memset(d,10,sizeof(d));
    head=0,tail=0;int x,y,xx,yy;
    q[++tail].bx=sx,q[tail].by=sy;
    d[sx][sy]=0;
    while(++head<=tail){
        x=q[head].bx,y=q[head].by;//空白所在点
        if(x==ex&&y==ey)return d[x][y];
        up(i,0,3){
            xx=x+dx[i],yy=y+dy[i];
            if(!a[xx][yy])continue;
            if(d[xx][yy]>=d[x][y]+1){
                d[xx][yy]=d[x][y]+1;
                q[++tail].bx=xx,q[tail].by=yy;
            }
        }
    }
    return d[ex][ey];
}
void init(){
    n=read(),m=read(),Q=read();
    up(i,1,n)up(j,1,m){
        a[i][j]=read();
        up(k,0,3)A[i][j][k]=++V;
    }
    int sx,sy,ex,ey;
    up(i,1,n)up(j,1,m){
        if(!a[i][j])continue;
        up(w,0,3){
            sx=i+dx[w],sy=j+dy[w];
            if(!a[sx][sy])continue;
            insert(A[i][j][w],A[sx][sy][w^1],1);
            up(z,0,3){
                if(w==z)continue;
                ex=i+dx[z],ey=j+dy[z];
                if(!a[ex][ey])continue;
                a[i][j]=0;
                int move=bfs(sx,sy,ex,ey)+1;
                if((move<=inf))insert(A[i][j][w],A[ex][ey][z^1],move);
                a[i][j]=1;
            }
        }
    }
}
int inx,qu[200000];
int dist[200000];
bool vis[200000];
int spfa(int S,int T){
    head=tail=0;qu[++tail]=S;
    memset(dist,10,sizeof(dist));
    memset(vis,0,sizeof(vis));
    dist[S]=0;int x;
    while(++head<=tail){
        x=qu[head];
        vis[x]=0;
        for(int i=linkk[x];i;i=e[i].next){
            if(dist[e[i].y]>=dist[x]+e[i].v){
                dist[e[i].y]=dist[x]+e[i].v;
                if(!vis[e[i].y]){
                    qu[++tail]=e[i].y;
                    vis[e[i].y]=1;
                }
            }
        }
    }
    return dist[T]>=inf?-1:dist[T];
}
void work(){
    int bx,by,sx,sy,tx,ty,x,y,xx,yy;
    while(Q--){
        bx=read(),by=read(),sx=read(),sy=read(),tx=read(),ty=read();
        if(sx==tx&&sy==ty){printf("0
");continue;}
        if(!a[sx][sy]||!a[tx][ty]){printf("-1
");continue;}
        int S=++V,T=++V;
        a[sx][sy]=0;
        up(k,0,3){
            x=sx+dx[k],y=sy+dy[k];
            if(!a[x][y])continue;
            int dis=bfs(bx,by,x,y);
            if(dis<inf)insert(S,A[sx][sy][k],dis);
        }
        a[sx][sy]=1;
        up(k,0,3){
            x=tx+dx[k],y=ty+dy[k];
            if(!a[x][y])continue;
            insert(A[tx][ty][k],T,0);
        }
        printf("%d
",spfa(S,T));
    }
}
int main(){
    freopen(FILE".in","r",stdin);
    freopen(FILE".out","w",stdout);
    init();
    work();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/chadinblog/p/5948812.html