NOIP2013华容道

news/2024/11/23 1:57:45/

NOIP2014华容道

说起来这道题还挺有难度的,我用了两个小时才把它AC,要是在赛场上的话。。。。这种题就果断放弃了

下面步入正题

题目描述 Description

小 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 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


-1

数据范围及提示 Data Size & Hint

【样例说明】
棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。
第一次游戏,空白格子的初始位置是 (3, 2)(图中空白所示),游戏的目标是将初始位置在(1, 2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2, 2)(图中红色的格子)上。
移动过程如下:

第二次游戏,空白格子的初始位置是(1, 2)(图中空白所示),游戏的目标是将初始位置在(2, 2)上的棋子(图中绿色圆圈所示)移动到目标位置 (3, 2)上。

要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置(2,2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置,游戏无法完成。

【数据范围】
对于 30%的数据,1 ≤ n, m ≤ 10,q = 1; 
对于 60%的数据,1 ≤ n, m ≤ 30,q ≤ 10; 
对于 100%的数据,1 ≤ n, m ≤ 30,q ≤ 500。

分享一下我的思路:

很明确的是要想把格子S移到目标位置T,首先得把白格子E移到S的旁边,在通过一系列的操作使格子S到达T

格子S想要走到与它相邻的k方向(left,right,up,down)上的格子,必须先把E格子通过w的花费移到那里,然后在用1的花费使S走到那 里,总花费为w+1,由于从一个格子向相邻方向上走一步的花费要多次使用,因此我们把它预处理成数组move[x][y][k][h],表示从(x,y)这个棋子,白格子在k方向上,使棋子走到h方向上相邻的格子的最少花费,这个可以用BFS预处理

有了这么多东西,能不能用BFS做呢?不行。从一个点走到相邻的节点的花费不一定是1,而且还受白格子所在方向的影响,所以就不再设状态为(x,y),而是(x,y,k),k表示白格子的方向,dist[x][y][k]存储走到这个状态的最小步数。很明显,从一个格子向h方向走的最小代价就是move[x][y][k][h],很明显这个状态只能转移到(x,y,other(h)),other(h)表示和h相反的方向,比如你向右走完一次,白格子一定在这个格子的左侧。

现在已经构建了一个又状态(x,y,k)构成的一张图,边权也已经算出来了,因此想要从出发点找一条到结束点的最短路径,可以用SPFA或堆Dijkstra,我更喜欢SPFA,因为一开始你要让四个状态入队,SFPA更方便一些,事实证明还是很快的

测试点#puzzle1.in  结果:    内存使用量:  364kB     时间使用量:  1ms     
测试点#puzzle10.in 结果: 内存使用量: 616kB 时间使用量: 0ms
测试点#puzzle11.in 结果: 内存使用量: 1004kB 时间使用量: 2ms
测试点#puzzle12.in 结果: 内存使用量: 1384kB 时间使用量: 7ms
测试点#puzzle13.in 结果: 内存使用量: 2024kB 时间使用量: 11ms
测试点#puzzle14.in 结果: 内存使用量: 2536kB 时间使用量: 28ms
测试点#puzzle15.in 结果: 内存使用量: 3052kB 时间使用量: 48ms
测试点#puzzle16.in 结果: 内存使用量: 3048kB 时间使用量: 52ms
测试点#puzzle17.in 结果: 内存使用量: 2028kB 时间使用量: 11ms
测试点#puzzle18.in 结果: 内存使用量: 2540kB 时间使用量: 27ms
测试点#puzzle19.in 结果: 内存使用量: 3052kB 时间使用量: 51ms
测试点#puzzle2.in 结果: 内存使用量: 492kB 时间使用量: 0ms
测试点#puzzle20.in 结果: 内存使用量: 2924kB 时间使用量: 50ms
测试点#puzzle3.in 结果: 内存使用量: 488kB 时间使用量: 1ms
测试点#puzzle4.in 结果: 内存使用量: 364kB 时间使用量: 1ms
测试点#puzzle5.in 结果: 内存使用量: 492kB 时间使用量: 0ms
测试点#puzzle6.in 结果: 内存使用量: 492kB 时间使用量: 0ms
测试点#puzzle7.in 结果: 内存使用量: 616kB 时间使用量: 1ms
测试点#puzzle8.in 结果: 内存使用量: 876kB 时间使用量: 4ms
测试点#puzzle9.in 结果: 内存使用量: 1388kB 时间使用量: 8ms
代码:

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#define up 1
#define down 2
#define left 3
#define right 4
#define maxn 35
#define inf 0x3f3f3f3fusing namespace std;struct node
{int x, y, k;
}t1, t2;
int pan[maxn][maxn], dist[maxn][maxn][5], Ex, Ey, move[maxn][maxn][5][5], deep[maxn][maxn], n, m;
bool in[maxn][maxn][5], done[maxn][maxn];
queue<node> q, qb;inline int other(int k)
{if(k==up)return down;if(k==down)return up;if(k==left)return right;if(k==right)return left;
}node go(node n, int k)
{node t=n;if(k==up)t.x--;if(k==down)t.x++;if(k==left)t.y--;if(k==right)t.y++;return t;
}int bfs(const node s, const node t)
{if(pan[s.x][s.y]==0 || pan[s.x][s.y]==0)return inf;memset(deep,0x3f,sizeof(deep));memset(done,0,sizeof(done));qb=*(new queue<node>);int i, j, k, h;node now, tmp;qb.push(s);deep[s.x][s.y]=0;done[s.x][s.y]=true;while(!qb.empty() && !done[t.x][t.y]){now=qb.front();qb.pop();for(k=1;k<=4;k++){tmp=go(now,k);if(!done[tmp.x][tmp.y] && pan[tmp.x][tmp.y]==1){done[tmp.x][tmp.y]=true;qb.push(tmp);deep[tmp.x][tmp.y] = deep[now.x][now.y]+1;}}}return deep[t.x][t.y];
}
void init()       //初始化move数组 
{memset(move,0x3f,sizeof(move));int i, j, k, h;for(i=1;i<=n;i++)for(j=1;j<=m;j++){if(pan[i][j]==0)continue;pan[i][j]=0; for(k=1;k<=4;k++){for(h=1;h<=4;h++){if(h<k){move[i][j][k][h]=move[i][j][h][k];continue;}t1=go((node){i,j},k);t2=go((node){i,j},h);if(pan[t1.x][t1.y]==0 || pan[t2.x][t2.y]==0)continue;move[i][j][k][h]=bfs(t1,t2)+1;}}pan[i][j]=1;}
}int spfa(const node S, const node T)
{if(S.x==T.x && S.y==T.y)return 0;node now, t;int i, j, k, h, ans;memset(dist,0x3f,sizeof(dist));memset(in,0,sizeof(in));if(pan[S.x][S.y]==0 || pan[T.x][T.y]==0)return inf;pan[S.x][S.y]=0;q=*(new queue<node>);for(k=1;k<=4;k++){t=(node){S.x,S.y,k};q.push(t), in[S.x][S.y][k]=true;dist[S.x][S.y][k]=bfs((node){Ex,Ey},go(S,k));}pan[S.x][S.y]=1;while(!q.empty()){now=q.front();q.pop();in[now.x][now.y][now.k]=false;for(h=1;h<=4;h++){t=go(now,h);t.k=other(h);if(dist[now.x][now.y][now.k] + move[now.x][now.y][now.k][h] < dist[t.x][t.y][other(h)]){dist[t.x][t.y][other(h)]=dist[now.x][now.y][now.k]+move[now.x][now.y][now.k][h];if(!in[t.x][t.y][t.k])q.push(t), in[t.x][t.y][t.k]=true;}}}ans=inf;for(k=1;k<=4;k++)ans = min(ans,dist[T.x][T.y][k]);return ans;
}
int main()
{int q, sx, sy, tx, ty, i, j, k, ans;scanf("%d%d%d",&n,&m,&q);for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&pan[i][j]);init();for(i=1;i<=q;i++){scanf("%d%d%d%d%d%d",&Ex,&Ey,&sx,&sy,&tx,&ty);ans=spfa((node){sx,sy},(node){tx,ty});if(ans<inf)printf("%d\n",ans);else printf("-1\n");}return 0;
}



http://www.ppmy.cn/news/550158.html

相关文章

CreateJS实现【益智类数字华容道小游戏】

系列文章 微信小程序(游戏)----拖拽拼图(图片分块和打乱顺序)微信小程序(游戏)----五子棋【taro react】(游戏) ---- 类2048游戏,看看在秦朝,功勋爵位你能到哪一级【taro react】(游戏) ---- 小游戏 2048 的实现1. 预览 1.1 在线h5 益智类数字华容道小游戏 在线h5 益…

最强大脑之《数字华容道》游戏Android端的具体实现

项目地址&#xff1a;https://github.com/ming723/NumberHrd 游戏效果&#xff1a; 前提摘要&#xff1a; 前两天粘贴出来了地址&#xff0c;不知道大家下载了没有&#xff0c;如果玩的话&#xff0c;是不是发现了几个潜在的问题&#xff0c;如果按完开始键后&#xff0c;不停…

python实现华容道游戏(v0.1)

#!python import copy ##Author: Lijun # #History: #V0.1 2021-12-15 #实现基础功能&#xff1a;一种初始化图形&#xff0c;可以人工操作游戏&#xff0c;游戏成功有提示 # # # # #Guanyu11 (*1) ;关羽2*1&#xff08;水平*竖直&#xff0c;下同) 横条&#xff0c;1个 #zh…

JAVA开发的华容道游戏

import java.awt.*;import java.applet.*;import java.awt.event.*; class People extends Button implements FocusListener //代表华容道人物的类。 { Rectangle rectnull; int left_x,left_y;//按扭的左上角坐标. int width,height; //按扭的宽和高. String name; int num…

Qt小游戏之数字华容道(百行代码搭雏形,可玩;含源码+注释)

文章目录 一、数字华容道&#xff0c;样图如下二、废话少说直接上代码1、首先是代码文件分析2、CLabel的源码3、CMainWindow的源码4、main文件 总结 一、数字华容道&#xff0c;样图如下 相信大家都知道华容道吧&#xff0c;数字华容道与其类似&#xff0c;源码在本文第二节&a…

Java游戏开发——华容道

游戏介绍&#xff1a; “华容道”是一款比较古老的游戏&#xff0c;其源于三国时期著名的历史故事。华容道作为一个经典游戏&#xff0c;各部分的设计都恰到好处&#xff0c;非常巧妙&#xff0c;因此成为世界游戏界的三大不可思议。 “华容道”游戏初始时曹操被围在华容道最…

python小游戏(华容道)

python基础运用 1、定义块 定义相应的块&#xff0c;每个方块实际就是一个按钮&#xff0c;所以继承Button类。每个方块的基本数据&#xff0c;除了方块的类型以外还有左上角的坐标&#xff0c;一旦确定方块的类型和坐标后&#xff0c;就可以确定方块对应的角色和位置了。方块…

如何用canvas制作一个华容道小游戏(乞丐版)

我大抵是废了φ(&#xff0e;&#xff0e;) &#xff0c;横竖都学不进去&#xff0c;上课知识不进脑子&#xff0c;学习光想划水摸鱼&#xff0c;心中仅剩的良知告诉我这样下去是铁定不行的哇&#xff0c;既然学不进去&#xff0c;何不打把游戏&#xff0c;既然要打游戏&#x…