NOIP 华容道

描述

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。

小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

  1. 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;
  2. 有些棋子是固定的,有些棋子则是可以移动的;
  3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EX_iEX?i?? 行第 EY_iEY?i?? 列,指定的可移动棋子的初始位置为第 SX_iSX?i?? 行第 SY_iSY?i?? 列,目标位置为第 TX_iTX?i?? 行第 TY_iTY?i?? 列。

假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

格式

输入格式

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;

接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。

接下来的 q 行,每行包含 6 个整数依次是 EX_iEX?i??、EY_iEY?i??、SX_iSX?i??、SY_iSY?i??、TX_iTX?i??、TY_iTY?i??,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

输出格式

输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出−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

Copy

样例输出1

2
-1

Copy

限制

每个测试点1s。

提示

###样例说明

棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。

  1. 第一次游戏,空白格子的初始位置是 (3, 2)(图中空白所示),游戏的目标是将初始位置在(1, 2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(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。

来源

NOIP 2013 提高组 day 2



  首先可以考虑全盘爆搜,让空白方块到处乱跑,状态要记录空白方块的位置和目标棋子的位置,所以状态总数为n2m2,时间复杂度为O(n2m2q).

  然后来想想优化,当空白方块跑到目标棋子周围时,再到处瞎跑没什么意义而且多个询问棋盘不会改变,所以呢,可以考虑预处理一下当目标棋子的位置为(i, j)时,空白方块在目标棋子a方向时移到b方向最少要的步数。花费一个O(n2m2)的时间去跑nm次bfs。

  这有什么用呢?我们先把空白棋子移到目标棋子周围然后就可以跑spfa了,spfa除了记录目标棋子的位置再记录一下空白棋子在哪个方向,转移的时候方向相反,这个距离就可以用之前预处理的结果了。这样总时间复杂度为O(n2m2 + qn2 + kqn2),其中k为spfa的常数。

Code

  1 #include<iostream>
  2 #include<fstream>
  3 #include<sstream>
  4 #include<string>
  5 #include<cstdio>
  6 #include<cstdlib>
  7 #include<cstring>
  8 #include<ctime>
  9 #include<cmath>
 10 #include<algorithm>
 11 #include<cctype>
 12 #include<vector>
 13 #include<stack>
 14 #include<set>
 15 #include<map>
 16 #include<queue>
 17 #ifndef WIN32
 18 #define Auto "%lld"
 19 #else
 20 #define Auto "%I64d"
 21 #endif
 22 using namespace std;
 23 typedef bool boolean;
 24 #define inf 0x3fffffff
 25 #define smin(a, b)    (a) = min((a), (b))
 26 #define smax(a, b)    (a) = max((a), (b))
 27
 28 template<typename T>
 29 class Matrix {
 30     public:
 31         T* p;
 32         int col, line;
 33         Matrix():p(NULL), col(0), line(0) {        }
 34         Matrix(int line, int col):line(line), col(col) {
 35             p = new T[(const int)(line * col)];
 36         }
 37
 38         T* operator [] (int pos) {
 39             return p + pos * col;
 40         }
 41 };
 42
 43 typedef class Point {
 44     public:
 45         int x;
 46         int y;
 47         Point(int x = 0, int y = 0):x(x), y(y) {        }
 48 }Point;
 49
 50 ifstream fin("puzzle.in");
 51 ofstream fout("puzzle.out");
 52
 53 int n, m, q;
 54 Matrix<boolean> walkable;
 55 int dis[35][35][4][4];
 56
 57 inline void init() {
 58     fin >> n >> m >> q;
 59     walkable = Matrix<boolean>(n, m);
 60     for(int i = 0; i < n; i++)
 61         for(int j = 0, x; j < m; j++) {
 62             fin >> x;
 63             if(x) walkable[i][j] = true;
 64             else walkable[i][j] = false;
 65         }
 66 }
 67
 68 const int mov[2][4] = {{1, -1, 0, 0}, {0, 0, 1, -1}};
 69
 70 boolean exceeded(int x, int y) {
 71     if(x < 0 || x >= n)    return true;
 72     if(y < 0 || y >= m)    return true;
 73     return false;
 74 }
 75
 76 int dep[35][35][35][35];
 77 queue<Point> que;
 78 queue<Point> que1;
 79
 80 boolean vis1[35][35];
 81 int dep1[35][35];
 82 inline int bfs1(Point s, Point t, Point g) {
 83     if(s.x == t.x && s.y == t.y)    return 0;
 84     memset(vis1, false, sizeof(vis1));
 85     dep1[s.x][s.y] = 0;
 86     vis1[s.x][s.y] = true;
 87     que.push(s);
 88     while(!que.empty()) {
 89         Point e = que.front();
 90         que.pop();
 91         for(int i = 0; i < 4; i++) {
 92             Point eu(e.x + mov[0][i], e.y + mov[1][i]);
 93             if(exceeded(eu.x, eu.y))    continue;
 94             if(!walkable[eu.x][eu.y])    continue;
 95             if(vis1[eu.x][eu.y])    continue;
 96             if(eu.x == g.x && eu.y == g.y)    continue;
 97             dep1[eu.x][eu.y] = dep1[e.x][e.y] + 1;
 98             if(eu.x == t.x && eu.y == t.y) {
 99                 while(!que.empty())    que.pop();
100                 return dep1[eu.x][eu.y];
101             }
102             vis1[eu.x][eu.y] = true;
103             que.push(eu);
104         }
105     }
106     return -1;
107 }
108
109 inline void init_dis() {
110     for(int i = 0; i < n; i++)
111         for(int j = 0; j < m; j++)
112             for(int p = 0; p < 4; p++) {
113                 Point w(i + mov[0][p], j + mov[1][p]);
114                 for(int q = 0; q < 4; q++) {
115                     Point t(i + mov[0][q], j + mov[1][q]);
116                     if(exceeded(w.x, w.y) || exceeded(t.x, t.y))    dis[i][j][p][q] = -1;
117                     else if(!walkable[w.x][w.y] || !walkable[i][j] || !walkable[t.x][t.y])    dis[i][j][p][q] = -1;
118                     else if(p == q)    dis[i][j][p][q] = 0;
119                     else dis[i][j][p][q] = bfs1(w, t, Point(i, j));
120                 }
121             }
122 }
123
124 boolean vis2[4][35][35];
125 int f[4][35][35];
126 queue<int> que2;
127 inline int spfa(Point s, Point t, Point w) {
128     memset(vis2, false, sizeof(vis2));
129     memset(f, 0x7f, sizeof(f));
130     for(int i = 0; i < 4; i++) {
131         Point e(s.x + mov[0][i], s.y + mov[1][i]);
132         if(exceeded(e.x, e.y))    continue;
133         if(!walkable[e.x][e.y])    continue;
134         f[i][s.x][s.y] = bfs1(Point(w.x, w.y), e, Point(s.x, s.y));
135         if(f[i][s.x][s.y] == -1)    f[i][s.x][s.y] = 0x7f7f7f7f;
136     }
137     for(int i = 0; i < 4; i++) {
138         que.push(s);
139         que2.push(i);
140     }
141     while(!que.empty()) {
142         Point e = que.front();
143         int ed = que2.front();
144         que.pop();
145         que2.pop();
146         vis2[ed][e.x][e.y] = false;
147         for(int i = 0; i < 4; i++) {
148             Point eu(e.x + mov[0][i], e.y + mov[1][i]);
149             int eud = i ^ 1;
150             if(exceeded(eu.x, eu.y))    continue;
151             if(!walkable[eu.x][eu.y])    continue;
152             if(dis[e.x][e.y][ed][i] == -1)    continue;
153             if(f[ed][e.x][e.y] + dis[e.x][e.y][ed][i] + 1 < f[eud][eu.x][eu.y]) {
154                 f[eud][eu.x][eu.y] = f[ed][e.x][e.y] + dis[e.x][e.y][ed][i] + 1;
155                 if(!vis2[eud][eu.x][eu.y]) {
156                     vis2[eud][eu.x][eu.y] = true;
157                     que.push(eu);
158                     que2.push(eud);
159                 }
160             }
161         }
162     }
163     int ret = inf;
164     for(int i = 0; i < 4; i++)
165         smin(ret, f[i][t.x][t.y]);
166     if(ret == inf)    return -1;
167     return ret;
168 }
169
170 int res = inf;
171 inline void solve() {
172     int wx, wy, sx, sy, tx, ty;
173     while(q--) {
174         res = inf;
175         fin >> wx >> wy >> sx >> sy >> tx >> ty;
176         wx--, wy--, sx--, sy--, tx--, ty--;
177         if(sx == tx && sy == ty) {
178             fout << "0" << endl;
179             continue;
180         }
181         fout << spfa(Point(sx, sy), Point(tx, ty), Point(wx, wy)) << endl;
182     }
183 }
184
185 int main() {
186     init();
187     init_dis();
188     solve();
189     return 0;
190 }
时间: 2024-10-14 07:00:18

NOIP 华容道的相关文章

搜索(另类状态BFS):NOIP 华容道

描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白

联赛之前的题表(已完成)汇总(可能有遗漏)

联赛之前的搞搞(其实是懒得分类) 博弈论 poj3537 poj1704 hdu5996两个插头 HDU1693 Eat the Trees COGS1283. [HNOI2004] 邮递员kdtree板子1941: [Sdoi2010]Hide and Seek旋转卡壳 pj2187凸包 cogs896 bzoj2829 信用卡凸包莫比乌斯反演基础 bzoj 4173 zhao gui lv bzoj 3529 mobiwus bzoj 4407 mobiwus bzoj 2818 mobiw

【noip】华容道

---恢复内容开始--- 描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格

【CodeVS 3290】【NOIP 2013】华容道

http://codevs.cn/problem/3290/ 据说2013年的noip非常难,但Purpleslz学长还是AK了.能A掉这道题真心orz. 设状态$(i,j,k)$表示目标棋子在$(i,j)$这个位置,空格在紧贴着目标棋子的$k$方向,$0≤k<4$. 因为目标棋子要移动,空格肯定在它旁边.往空格的方向走一步,空格便出现在它另一边.对于这两个状态连边,边权为1. 为了使目标棋子向某一方向移动,需要目标棋子不动,空格从紧贴着目标棋子的某一方向移动到紧贴着目标棋子的另一个方向.对于固

noip 2013 华容道

/*双向bfs (得分和单项的一样多....)70*/ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 35 #define maxm 810010 using namespace std; int n,m,q,g[maxn][maxn]; int X,Y,sx,sy,ex,ey,falg,vis[maxn][maxn]; int xx[4]

[RT][NOIP2013]华容道

1.题面 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间.小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空

NOIp 2013 Day2 解题报告

NOIp 2013 Day2 解题报告 1.   积木大赛 每次只要选取连续最大的一段区间即可. 继续归纳可得,答案为∑i=1nmax{0,hi-hi-1} 复杂度O(N) 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable/

NOIP模拟3

期望得分:30+90+100=220 实际得分:30+0+10=40 T1智障错误:n*m是n行m列,硬是做成了m行n列 T2智障错误:读入三个数写了两个%d T3智障错误:数值相同不代表是同一个数 既眼瘸又脑残,NOIP这样后悔去吧! T1 n*m网格,有S种颜色. 按从上到下,从左到右的顺序涂色. 相邻的相同色块可得一份,问最大得分 n,S<=100000,m<=4 只有最多4列 1列:顺着涂 2列:先涂可以涂偶数个 3列:先涂%3=0的,然后一个%3=1和一个%3=2的组合,剩余的顺着涂

写在开学后:暑假没有什么卵用的总结以及NOIP复赛前的计划

emmmm暑假干了点什么呢? 7月在机房培训,听的基本是各种没有学过的东西...所以基本都是懂了个大概,没有具体的代码实现...23号之后休息,除了出去玩之外也没有干啥... 8月去雅礼集训.emmm讲的基本都是以前听过的东西和已经学过的东西...所以现在还是懂了个大概...至于收获嘛,就是有了十几天的考试经验(虽然总结被我忘到脑袋后面了) 现在开学了,在新知识的学习上可以说我这两个月基本什么都没有学? 所以说更是要赶进度了= = 11月就是NOIP了,大概是没有什么压力的?不过今年的NOIP,