NC16536. [NOIP2013]华容道
描述
输入描述
第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n,m,q ;
接下来的 n 行描述一个 n x m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态, 0 表示该格子上的棋子是固定的, 1 表示该格子上的棋子可以移动或者该格子是空白的。
接下来的 q 行,每行包含 6 个整数依次是 EXi,EYi,SXi,SYi,TXi,TYi ,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。
输出描述
共 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出 −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
说明:
C++(g++ 7.5.0) 解法, 执行用时: 22ms, 内存消耗: 536K, 提交时间: 2023-07-27 16:28:39
#include<bits/stdc++.h> using namespace std; const int N=35,M=4010; int n,m,q,mp[N][N],dis[N][N],dist[M]; bool vis[M]; int e,to[M*5],nxt[M*5],val[M*5],hd[M]; int dx[5]={-1,1,0,0}; int dy[5]={0,0,-1,1}; void add(int x,int y,int w){ to[++e]=y; nxt[e]=hd[x]; val[e]=w; hd[x]=e; } void bfs(int ei,int ej,int si,int sj,int dir){ memset(dis,0,sizeof(dis)); queue<pair<int,int> >q; q.push(make_pair(ei,ej)); dis[ei][ej]=1; while(!q.empty()){ pair<int,int>w=q.front(); q.pop(); int x=w.first,y=w.second; for(int i=0;i<4;i++){ int xx=x+dx[i],yy=y+dy[i]; if(!mp[xx][yy]||dis[xx][yy]||xx==si&&yy==sj) continue; dis[xx][yy]=dis[x][y]+1; q.push(make_pair(xx,yy)); } } if(dir==4) return; for(int i=0;i<4;i++){ int xx=si+dx[i],yy=sj+dy[i]; if((xx==ei&&yy==ej)||!dis[xx][yy]) continue; add(si*30*4+sj*4+dir,si*30*4+sj*4+i,dis[xx][yy]-1); } add(si*30*4+sj*4+dir,ei*30*4+ej*4+(dir^1),1); return; } void spfa(int x,int y){ memset(dist,0x3f,sizeof(dist)); memset(vis,0,sizeof(vis)); queue<int>q; for(int i=0;i<4;i++){ if(!dis[x+dx[i]][y+dy[i]]) continue; int id=x*30*4+y*4+i; q.push(id); dist[id]=dis[x+dx[i]][y+dy[i]]-1; vis[id]=1; } while(!q.empty()){ int id=q.front(); q.pop(); vis[id]=0; for(int i=hd[id];i;i=nxt[i]){ int nxid=to[i],nxval=val[i]; if(dist[nxid]>dist[id]+nxval){ dist[nxid]=dist[id]+nxval; if(vis[nxid]) continue; vis[nxid]=1; q.push(nxid); } } } return; } 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",&mp[i][j]); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(!mp[i][j]) continue; if(mp[i-1][j]) bfs(i-1,j,i,j,0); if(mp[i+1][j]) bfs(i+1,j,i,j,1); if(mp[i][j-1]) bfs(i,j-1,i,j,2); if(mp[i][j+1]) bfs(i,j+1,i,j,3); } } while(q--){ int ex,ey,sx,sy,tx,ty; scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty); if(sx==tx&&sy==ty){ puts("0"); continue; } bfs(ex,ey,sx,sy,4); spfa(sx,sy); int ans=0x3f3f3f3f; for(int i=0;i<4;i++) ans=min(ans,dist[tx*30*4+ty*4+i]); (ans==0x3f3f3f3f)?puts("-1"):printf("%d\n",ans); } return 0; }
C++ 解法, 执行用时: 917ms, 内存消耗: 5508K, 提交时间: 2022-02-07 15:07:58
#include<bits/stdc++.h> using namespace std; int n,m,p; int mapp[31][31]; bool mark[31][31][31][31]; int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0}; struct data{ int x,y; int kx,ky; int tim; }a[810001]; bool judge(int x,int y,int kx,int ky)//判断能不能移动 { if(kx<1||ky<1||kx>n||ky>m||mapp[kx][ky]==0) return 0; if(mark[x][y][kx][ky]) return 0; mark[x][y][kx][ky]=1; return 1; } void search() { memset(mark,0,sizeof(mark)); int t=0,w=0; int ex,ey;//目标位置 int x,y,kx,ky;//移动块,空白块 scanf("%d%d%d%d%d%d",&a[0].kx,&a[0].ky,&a[0].x,&a[0].y,&ex,&ey); if(ex==a[0].x&&ey==a[0].y){//如果移动块一开始就在目标位置 cout<<0<<endl; return; } mark[a[0].x][a[0].y][a[0].kx][a[0].ky]=1; while(t<=w){ for(int i=0;i<4;i++){ x=a[t].x;//移动块的位置 y=a[t].y; kx=a[t].kx+xx[i];//控制空白块四向移动 ky=a[t].ky+yy[i]; if(x==kx&&y==ky){//如果空白块能移动到移动块,移动块到空白块的位置上 x=a[t].kx; y=a[t].ky; } if(judge(x,y,kx,ky)){//空白块不在移动块边上,但是状态合法,存储改图 w++; a[w].x=x; a[w].y=y; a[w].kx=kx; a[w].ky=ky; a[w].tim=a[t].tim+1; if(x==ex&&y==ey){ cout<<a[w].tim<<endl; return; } } } t++; } cout<<-1<<endl; return; } int main() { cin>>n>>m>>p; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d", &mapp[i][j]); } } for(int i=1;i<=p;i++){ search(); } }