唔马上要考noip了 泪目。希望rp++。
莫名被archer圈粉。
今天终于搞定这道题了 呼。。。
所以orz当年4(+3)神犇。
题目描述 Description
小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。
小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:
在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;
有些棋子是固定的,有些棋子则是可以移动的;
任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。
给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EX_i 行第 EY_i 列,指定的可移动棋子的初始位置为第 SX_i 行第 SY_i 列,目标位置为第 TX_i 行第 TY_i 列。
假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。
输入描述 Input Description
第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;
接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。
接下来的 q 行,每行包含 6 个整数依次是 EX_i、EY_i、SX_i、SY_i、TX_i、TY_i,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。
输出描述 Output Description
输出有 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
对于 30%的数据,1 ≤ n, m ≤ 10,q = 1;
对于 60%的数据,1 ≤ n, m ≤ 30,q ≤ 10;
对于 100%的数据,1 ≤ n, m ≤ 30,q ≤ 500。
60%很好说吧。bfs就可以。。直接上代码了!【得了65 是要闹哪样】
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
//by mars_ch
using namespace std;
struct data
{
int x,y;
int kx,ky;
int dis;
}a;
int n,m,k;
int ex,ey,sx,sy,tx,ty;
int map[30][30];
int vis[30][30][30][30];
int dx[5]={1,-1,0,0};
int dy[5]={0,0,1,-1};
queue<data> q;
void bfs()
{
while(!q.empty()) q.pop();
memset(vis,0,sizeof(vis));
data t;
t.x=sx,t.y=sy;
t.kx=tx,t.ky=ty;
t.dis=0;
if(t.x == ex && t.y==ey){
printf("0\n");
return;
}
vis[sx][sy][tx][ty]=1;
q.push(t);
while(!q.empty())
{
data v=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int nx=v.x,ny=v.y;
int bx=v.kx+dx[i],by=v.ky+dy[i];;
if(bx == nx && by == ny)
{
nx=v.kx,ny=v.ky;
}
if(nx<=n && ny<=m && nx>0 && ny>0 && bx<=n && bx>0 && by<=m && by>0 && map[nx][ny]==1 && map[bx][by] == 1 &&!vis[nx][ny][bx][by])
{
vis[nx][ny][bx][by]=1;
data u;
u.x=nx,u.y=ny,u.kx=bx,u.ky=by;
u.dis=v.dis+1;
if(nx == ex && ny == ey)
{
printf("%d\n",u.dis);
return;
}
q.push(u);
}
}
}
printf("-1\n");
return;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&map[i][j]);
}
}
while(k--)
{
scanf("%d%d%d%d%d%d",&tx,&ty,&sx,&sy,&ex,&ey);
bfs();
}
return 0;
}
然后来说正解:
好吧,又看了正解yy了很久。
然后网上的代码都好繁琐啊 泪目。。
所以 根据60分算法观察,我们搜索到了许多并不会移动的状态。并且每次询问的 棋盘式固定的也就是可移动的棋子是固定的。
我们又拥有2种操作:
1.将空白格子移至目标棋子想要前进的方向。
2.空白格子和目标棋子相邻,交换【一起移动】
对于每个合法点A(x,y),枚举一个E(ex,ey)表示相邻的空格的位置,和一个T(tx,ty)表示要把目标棋子从这个格子移向的位置【方向】。
所以如果将所有的状态都处理出来,那么每个格子到每个格子就先定了。
所以 我们只需要建边跑一边spfa就OK了!
注意状态时3维的啦~
上代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 1000000007
//by mars_ch
using namespace std;
int n,m,k;
int ex,ey,sx,sy,tx,ty;
int map[35][35],ha[32][35][5],dis[35][35],d[5005],inq[5005];
int dx[5]={1,-1,0,0};
int dy[5]={0,0,1,-1};
struct data
{
int f,t,w,nxt;
}e[300005];
int first[100005],tot;
void add(int a,int b,int c)
{
e[tot].f=a,e[tot].t=b,e[tot].w=c;
e[tot].nxt=first[a],first[a]=tot++;
}
int bfs(int stx,int sty,int edx,int edy)
{
if(stx == edx && sty == edy) return 0;
queue<pair<int,int> > q;
memset(dis,-1,sizeof(dis));
q.push(make_pair(stx,sty));
dis[stx][sty]=0;
while(!q.empty())
{
int nx=q.front().first,ny=q.front().second;
q.pop();
for(int i=0;i<4;i++){
int xx=nx+dx[i],yy=ny+dy[i];
if(!map[xx][yy] || dis[xx][yy]!=-1)continue;
dis[xx][yy]=dis[nx][ny]+1;
if(xx == edx && yy==edy){
return dis[xx][yy];
}
q.push(make_pair(xx,yy));
}
}
return inf;
}
void pre_bfs(int x,int y)
{
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(!map[nx][ny]) continue;
for(int j=0;j<4;j++){
int xx=x+dx[j],yy=y+dy[j];
if(!map[xx][yy]) continue;
int temp=bfs(nx,ny,xx,yy);
if(temp!=inf){
add(ha[x][y][i],ha[xx][yy][j^1],temp+1);
}
}
}
}
int spfa(int s,int t)
{
queue<int> q;
for(int i=1;i<=t;i++)
{
d[i]=inf;
inq[i]=0;
}
d[s]=0;
q.push(s);
inq[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
inq[u]=0;
for(int i=first[u];i!=-1;i=e[i].nxt)
{
int t=e[i].t;
if(d[t]>d[u]+e[i].w){
d[t]=d[u]+e[i].w;
if(!inq[t]){
inq[t]=1;
q.push(t);
}
}
}
}
if(d[t] == inf) return -1;
else return d[t];
}
int main()
{
int h=0;
scanf("%d%d%d",&n,&m,&k);
memset(first,-1,sizeof(first));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&map[i][j]);
for(int d=0;d<4;d++)
{
ha[i][j][d]=++h;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(map[i][j]){
map[i][j]=0;
pre_bfs(i,j);
map[i][j]=1;
}
}
}
while(k--)
{
scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
if(sx == tx && sy==ty){
puts("0");
continue;
}
int S=++h,T=++h;
map[sx][sy]=0;
for(int i=0;i<4;i++)
{
int nx=sx+dx[i],ny=sy+dy[i];
if(!map[nx][ny]) continue;
int temp=bfs(ex,ey,nx,ny);
if(temp!=inf){
add(S,ha[sx][sy][i],temp);
}
}
map[sx][sy]=1;
for(int i=0;i<4;i++)
{
int nx=tx+dx[i],ny=ty+dy[i];
if(map[nx][ny]){
add(ha[tx][ty][i],T,0);
}
}
printf("%d\n",spfa(S,T));
}
return 0;
}