codevs 3290 noip 2013 Day2 T3华容道
2016-11-06 16:16
344 查看
唔马上要考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 是要闹哪样】
然后来说正解:
好吧,又看了正解yy了很久。
然后网上的代码都好繁琐啊 泪目。。
所以 根据60分算法观察,我们搜索到了许多并不会移动的状态。并且每次询问的 棋盘式固定的也就是可移动的棋子是固定的。
我们又拥有2种操作:
1.将空白格子移至目标棋子想要前进的方向。
2.空白格子和目标棋子相邻,交换【一起移动】
对于每个合法点A(x,y),枚举一个E(ex,ey)表示相邻的空格的位置,和一个T(tx,ty)表示要把目标棋子从这个格子移向的位置【方向】。
所以如果将所有的状态都处理出来,那么每个格子到每个格子就先定了。
所以 我们只需要建边跑一边spfa就OK了!
注意状态时3维的啦~
上代码
莫名被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; }
相关文章推荐
- 一道搜索题【2013 noip提高组 DAY2 t3】华容道
- 一道搜索题【2013 noip提高组 DAY2 t3】华容道
- NOIP2013 DAY2 T3 华容道(PUZZLE) BFS+SPFA
- NOIP2013 D2T3 codevs 3290 洛谷 P1979 华容道 题解报告
- 【NOIP 2013 DAY2 T3】 华容道(spfa)
- 【CodeVS 3290】【NOIP 2013】华容道
- NOIP2013 Day2 T3 华容道
- 总结(【中山市选2014】投票 【中山市选2014】dwarf tower 【中山市选2014】图 【NOIP2013提高组day2】华容道)
- [noip2013][codevs3290]华容道 bfs+spfa
- NOIP2013提高组D2T3 华容道
- 【NOIP2013 day2】华容道 题解
- NOIP2013复赛提高组day2(A:积木大赛 B:花匠 C:华容道)
- 【NOIP2013提高组day2】华容道
- 【华容道】题解(NOIP2013提高组day2)
- JZOJ3537 【NOIP2013提高组day2】华容道 暴力+压缩路径优化
- [Vijos1864]NOIP2013提高Day2华容道
- 【codevs 3289】[NOIP 2013 day2 T2] 花匠(dp)
- 【NOIP2013提高组day2】华容道
- 【NOIP2013提高组day2】【JZOJ 3537】华容道
- 【最短路】【bfs】[NOIP2013] codevs3290 华容道