1 #include<iostream>
2 #include<cstdlib>
3 #include<algorithm>
4 #include<cmath>
5 #include<cstring>
6 #incude<stdio.h>
7 #include<map>
8 #include<vector>
9
using
namespace std;
10
11 vector<
int> adj[
6][
999997];
12
13
int r,c,cnt;
14
int MOD=
999997;
15
16
//
这里定义方向向量,便于搜索
17
int dirx[]={-
1,
1,
0,
0};
18
int diry[]={
0,
0,-
1,
1};
19
20
//
定义一个结构体,存储地图
21
struct pp
22 {
23
bool mat[
20][
20];
24 };
25
26
struct bl
27 {
28
int num;
29
short list[
145][
2];
30
bool
operator <(
const bl &temp)
const
31 {
32
return num<temp.num;
33 }
34 };
35
36 pp nw;
37
38
struct qq
39 {
40
int id1,id2;
41 };
42
43 qq list[
200],queue[
200];
44
45
//
这里标记是否经历过
46
bool visit[
13][
13];
47
48
int f[
20][
20],temp1,temp2,temp,ans[
200][
200][
2],num[
200],cont;
49
50
bool t_dfs(
int a[],
int id1,
int id2,
int na[],
int dir,pp now,
int deep,
int ndeep);
51
bool dfs(
int a[],pp nw,
int ndeep);
52
53
void bfs(
int id1,
int id2,pp nw)
54 {
55
int i,j,s,p,q;
56
//
将这个空白方块入队列,并标记为已经访问
57
queue[
0].id1=id1;
58 queue[
0].id2=id2;
59 visit[id1][id2]=
true;
60 temp1=temp2=
0;
61 temp=
1;
62
while(temp1<=temp2)
63 {
64
for(i=temp1;i<=temp2;i++)
65 {
66
//
分别对四个方向进行BFS
67
for(j=
0;j<
4;j++)
68 {
69 id1=queue[i].id1+dirx[j];
70 id2=queue[i].id2+diry[j];
71
//
判断搜索的点是否越界
72
if(id1>=
0&&id1<r&&id2>=
0&&id2<c)
73 {
74
//
如果延拓的这一点是空地而且未被访问的话
75
if(visit[id1][id2]==
false&&nw.mat[id1][id2]==
0)
76 {
77
//
标记为已访问,并且入队列
78
visit[id1][id2]=
true;
79 queue[temp].id1=id1;
80 queue[temp++].id2=id2;
81 }
82 }
83 }
84 }
85
//
这里的含义是,去掉一个已经出队的点,增加新入队的点
86
temp1=temp2+
1;
87 temp2=temp-
1;
88 }
89 }
90
91
int main()
92 {
93
int i,j,ncnt,a[
5];
94 scanf(
"
%d%d
",&r,&c);
95 cnt=
0;
96 memset(f,-
1,
sizeof(f));
97
for(i=
0;i<r;i++)
98 {
99
for(j=
0;j<c;j++)
100 {
101 scanf(
"
%d
",&nw.mat[i][j]);
102
if(nw.mat[i][j]==
0)
103 {
104 list[cnt].id1=i;
105 list[cnt].id2=j;
106 f[i][j]=cnt++;
107 }
108 }
109 }
110 memset(num,
0,
sizeof(num));
111 cont=
0;
112
//
orz为真值,看是为true还是false
113
int orz=dfs(a,nw,
0);
114
if(orz>
0)
115 {
116
//
总共需要行进几轮
117
printf(
"
%d\n
",cont);
118
for(i=
0;i<cont;i++)
119 {
120
//
每一轮的行进步数
121
printf(
"
%d:
",num[i]);
122
//
加1的原因是,那个数组是从0下标开始计数的
123
for(j=
0;j<num[i];j++)
124 printf(
"
(%d,%d)
",ans[i][j][
0]+
1,ans[i][j][
1]+
1);
125 printf(
"
\n
");
126 }
127 }
128
return
0;
129 }
130
131
bool t_dfs(
int a[],
int id1,
int id2,
int na[],
int dir,pp now,
int deep,
int ndeep)
132 {
133
int i,j,x,y,id,b[
6];
134 ans[ndeep][deep][
0]=id1;
135 ans[ndeep][deep][
1]=id2;
136
//
将目前的点标记为石头,表明已经走过
137
now.mat[id1][id2]=
1;
138
//
对已经选定好的方向进行搜索
139
x=id1+dirx[dir];
140 y=id2+diry[dir];
141
if(x<
0||x>=r||y<
0||y>=c)
142 {
143
//
如果已经出界,记录答案
144
ans[ndeep][deep+
1][
0]=x;
145 ans[ndeep][deep+
1][
1]=y;
146 num[ndeep]=deep+
2;
147
if(num[ndeep]>
3)
148 {
149
if(dfs(b,now,ndeep+
1))
150
return
true;
151 }
152
//
不行的话,重新标记为空地
153
now.mat[id1][id2]=
0;
154
return
false;
155 }
156
//
如果没有越界而且这里为空地的话,则可能满足题目条件
157
if(now.mat[x][y]==
0)
158 {
159
//
搜索深度每次加深1个单位
160
if(t_dfs(a,x,y,na,dir,now,deep+
1,ndeep))
return
true;
161
//
否则,退回到原来的状态
162
now.mat[id1][id2]=
0;
163
return
false;
164 }
165
//
如果不是空地的话,朝四个方向搜索
166
else
167 {
168
for(i=
0;i<
4;i++)
169 {
170 x=id1+dirx[i];
171 y=id2+diry[i];
172
if(x<
0||x>=r||y<
0||y>=c)
173 {
174 ans[ndeep][deep+
1][
0]=x;
175 ans[ndeep][deep+
1][
1]=y;
176
if(num[ndeep]>
3)
177 {
178
if(dfs(b,now,ndeep+
1))
return
true;
179 }
180 }
181
else
if(now.mat[x][y]==
0)
182 {
183
if(t_dfs(a,x,y,na,i,now,deep+
1,ndeep))
return
true;
184 }
185 }
186
//
否则,将其重新标为空地,返回false
187
now.mat[id1][id2]=
0;
188
return
false;
189 }
190 }
191
192
bool dfs(
int a[],pp nw,
int ndeep)
193 {
194
int siz,value=
0,i,j,s=
0,cou=
0,na[
5],b[
6],id,
in=
1000000000;
195 pp now;
196 bl block[
20];
197 a[
0]=a[
1]=a[
2]=a[
3]=a[
4]=
0;
198
//
利用一个数组模拟30进制存储
199
for(i=
0;i<r;i++)
200 {
201
for(j=
0;j<c;j++)
202 {
203
if(nw.mat[i][j]==
0)
204 {
205
int id=f[i][j];
206 a[id/
30]+=(
1<<(id%
30));
207 }
208 }
209 }
210
if(a[
0]==
0&&a[
1]==
0&&a[
2]==
0&&a[
3]==
0&&a[
4]==
0)
211 {
212 cont=ndeep;
213
return
true;
214 }
215
//
否则,按照键值存储一个状态
216
for(i=
4;i>=
0;i--)
217 value=(((
long
long)((
1<<
30)%MOD)*(
long
long)value)%MOD+a[i])%MOD;
218 siz=adj[
0][value].size();
219
//
这是判断是否越出了五位的界么?这个逻辑实现的功能还没怎么看懂
220
for(i=
0;i<siz;i++)
221 {
222
for(j=
0;j<
5;j++)
223 {
224
if(adj[j][value][i]!=a[j])
break;
225 }
226
if(j>=
5)
break;
227 }
228
if(i<siz)
return adj[
5][value][i];
229 memset(visit,
false,
sizeof(visit));
230
for(i=
0;i<r;i++)
231
for(j=
0;j<c;j++)
232 {
233
//
对于每一个还没有遍历,且为空地的地方,进行bfs扫描
234
if(visit[i][j]==
false&&nw.mat[i][j]==
0)
235 {
236 bfs(i,j,nw);
237
//
每次新增的块
238
block[cou].num=temp;
239
//
将对每一点搜索的新增的块都加入到list中
240
for(s=
0;s<temp;s++)
241 {
242 block[cou].list[s][
0]=queue[s].id1;
243 block[cou].list[s][
1]=queue[s].id2;
244 }
245 cou++;
246 }
247 }
248
//
对每一个块进行分析
249
for(i=
0;i<cou;i++)
250 {
251
//
利用变量orz存储由这个方块延拓的遇到边界的次数(神牛就是神牛,变量名都那么精彩)
252
int orz=
0;
253
//
对那一块所有新增加的块进行分析
254
for(j=
0;j<block[i].num;j++)
255 {
256
if(block[i].list[j][
0]==
0)
257 orz++;
258
else
if(block[i].list[j][
0]==r-
1)
259 orz++;
260
else
if(block[i].list[j][
1]==
0)
261 orz++;
262
else
if(block[i].list[j][
1]==c-
1)
263 orz++;
264 }
265
//
得到块数最小的点
266
if(
in>block[i].num)
267 {
268
in=block[i].num;
269 id=i;
270 }
271
//
如果只能触及到一个边界,那么是不行的
272
if(orz<=
1)
return
false;
273 }
274 }
275
//
这里给出了我们的AI策略,每次选取延拓方块最小的,这样最不容易导致出现"石头阻挡"或者"经历过的点,绕不回来"的毛病
276
swap(block[id],block[
0]);
277
for(i=
0;i<block[
0].num;i++)
278 {
279
//
对块延拓出的边界点进行处理,广度搜索,并存储在a[]中
280
if(block[
0].list[i][
0]==
0)
281 {
282 memset(na,
0,
sizeof(na));
283 now=nw;
284 num[ndeep]=
0;
285 ans[ndeep][num[ndeep]][
0]=-
1;
286 ans[ndeep][num[ndeep]++][
1]=block[
0].list[i][
1];
287
//
如果这条路径可达的话
288
if(t_dfs(a,block[
0].list[i][
0],block[
0].list[i][
1],na,
1,now,
1,ndeep))
289 {
290
for(j=
0;j<
5;j++)
291 adj[j][value].push_back(a[j]);
292 adj[
5][value].push_back(
1);
293
return
true;
294 }
295 }
296
if(block[
0].list[i][
0]==r-
1)
297 {
298 memset(na,
0,
sizeof(na));
299 now=nw;
300 num[ndeep]=
0;
301 ans[ndeep][num[ndeep]][
0]=r;
302 ans[ndeep][num[ndeep]++][
1]=block[
0].list[i][
1];
303
if(t_dfs(a,block[
0].list[i][
0],block[
0].list[i][
1],na,
0,now,
1,ndeep))
304 {
305
for(j=
0;j<
5;j++)
306 adj[j][value].push_back(a[j]);
307 adj[
5][value].push_back(
1);
308
return
true;
309 }
310 }
311
if(block[
0].list[i][
1]==
0)
312 {
313 memset(na,
0,
sizeof(na));
314 now=nw;
315 num[ndeep]=
0;
316 ans[ndeep][num[ndeep]][
0]=block[
0].list[i][
0];
317 ans[ndeep][num[ndeep]++][
1]=-
1;
318
if(t_dfs(a,block[
0].list[i][
0],block[
0].list[i][
1],na,
3,now,
1,ndeep))
319 {
320
for(j=
0;j<
5;j++)
321 adj[j][value].push_back(a[j]);
322 adj[
5][value].push_back(
1);
323
return
true;
324 }
325 }
326
if(block[
0].list[i][
1]==c-
1)
327 {
328 memset(na,
0,
sizeof(na));
329 now=nw;
330 num[ndeep]=
0;
331 ans[ndeep][num[ndeep]][
0]=block[
0].list[i][
0];
332 ans[ndeep][num[ndeep]++][
1]=c;
333
if(t_dfs(a,block[
0].list[i][
0],block[
0].list[i][
1],na,
2,now,
1,ndeep))
334 {
335
for(j=
0;j<
5;j++)
336 adj[j][value].push_back(a[j]);
337 adj[
5][value].push_back(
1);
338
return
true;
339 }
340 }
341 }
342
for(j=
0;j<
5;j++)
343 adj[j][value].push_back(a[j]);
344 adj[
5][value].push_back(
0);
345
return
false;
346 }
347
348
349
350
351
352