吴昊品游戏核心算法 Round 13(特别篇)—— 另一种迷宫游戏AI(queue容器+BFS)
另外一种迷宫游戏来自(HDOJ的1072)。刚才那个应该还不能说是游戏吧!因为只是一些迷宫类游戏的关键技术,还不具备有游戏性(所谓游戏性,可以参 考任天堂公司给出的定义)。这里,Ignatius给出了游戏的规则——五个数字标注了五种不同的图标(这里考虑五种位图,数字0代表墙,数字1代表可以 通过的路线,数字2代表起始的地方,数字3代表Ignatius的目标位置,而数字4代表了一种很新颖的道具,这个道具我们接了之后,可以将时间重置为6 分钟)这里考虑一点,最开始的时间为6分钟,每走一步要减少一分钟,我们必须要在规定的时间之内走到终点(当然,这里有RESET的装备),不然的话,炸 弹就会爆炸,我们需要计算出到达目标的最优解(这里的最优参量定义为最小时间)
和前面一款游戏比较类似,这里的游戏有一种“逃离迷宫”的感觉。同样地,我们定义一种二维数组mark[][]来定义每个格子所代表的最优状态,方向数组 当然是少不了的。不同的是,我们考虑将node结构体定义两个描述时间的变量,用time表示还剩下的时间,而用cnt表示需要花费的时间。也许,你觉得 这是不是具有重复定义的嫌疑?不是的,在代码中我阐述了为什么要定义两个表述时间的变量。而在这里,关于时间的最优解,确实不好界定,这里是否可以达到最 优呢?不知道能不能通过理论方法来证明出来(但是毕竟这里对于每一步都考虑优化了),但是由于对于给定的样例都AC了,可以说,如果样例不是太强的话,应 该是没有问题的。
1 #include<iostream>
2 //这里还是运用队列容器来实现
3 #include<queue>
4 using namespace std;
5
6 //首先是地图map[][],mark[][]保存到达该点时所剩的时间,n,m为地图的实际的长和宽,(si,sj)为开始的点,mins
7 int map[9][9],mark[9][9],n,m,mins,si,sj;
8
9 //方向数组
10 int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
11
12 struct node
13 {
14 //time 剩余时间;cnt 已花时间
15 int x,y,time,cnt;
16 };
17
18 node f;
19
20 void bfs()
21 {
22 f.x=si;
23 f.y=sj;
24 //已花的时间为0,而剩余的时间为6
25 f.cnt=0;
26 f.time=6;
27 queue<node> q;
28 q.push(f);
29 //这里标注第一个点的所剩的时间
30 mark[si][sj]=6;
31 //如果队列整个空了,则退出
32 while(!q.empty())
33 {
34 node t=q.front();
35 q.pop();
36 if(map[t.x][t.y]==3)
37 {
38 //找到终点了,如果还剩余时间的话,将已经花费的时间输出
39 if(t.time>0)
40 {
41 mins=t.cnt;
42 return;
43 }
44 else continue;
45 }
46 //如果踩到了重置时间的机关,则重置时间,并标记当前位置的时间
47 if(map[t.x][t.y]==4)
48 {
49 t.time=6;
50 mark[t.x][t.y]=6;
51 }
52 for(int k=0;k<4;k++)
53 {
54 //定义一个NEXT结点,这个在前面的吴昊系列已经阐述过了
55 node b;
56 b.x=t.x+dir[k][0];
57 b.y=t.y+dir[k][1];
58 //将已经花费的时间++,而剩余的时间--
59 b.cnt=t.cnt+1;
60 b.time=t.time-1;
61 /*
62 入队的条件,这里有如下一些条件:
63 (1)首先,必须在迷宫的范围之内
64 (2)这个位置不是一堵墙
65 (3)目前还存在剩余时间
66 (4)这个位置标识的最小需要时间必须小于实际的剩余时间(这样才能起到不断优化的作用),由此能不能就判断出是最小值呢?不一定,所以这里也置疑吧!
67 */
68 if(b.x<=n&&b.x>0&&b.y<=m&&b.y>0&&map[b.x][b.y]!=0&&t.time>0&&mark[b.x][b.y]<b.time)
69 {
70 mark[b.x][b.y]=b.time;
71 q.push(b);
72 }
73 }
74 }
75 }
76
77 int main()
78 {
79 int t;
80 //样例的总数
81 cin>>t;
82 while(t--)
83 {
84 //地图的长与宽
85 cin>>n>>m;
86 for(int i=1;i<=n;i++)
87 {
88 for(int j=1;j<=m;j++)
89 {
90 //将地图中的元素进行分类
91 cin>>map[i][j];
92 if(map[i][j]==2)
93 {
94 si=i;
95 sj=j;
96 mark[i][j]=0;
97 }
98 }
99 }
100 //设置一个极大的时间,如果这个时间没有经过任何改动的话,判定出死亡了
101 mins=1000;
102 bfs();
103 if(mins!=1000)
104 cout<<mins<<endl;
105 else cout<<"-1"<<endl;
106 }
107 return 0;
108 }
2 //这里还是运用队列容器来实现
3 #include<queue>
4 using namespace std;
5
6 //首先是地图map[][],mark[][]保存到达该点时所剩的时间,n,m为地图的实际的长和宽,(si,sj)为开始的点,mins
7 int map[9][9],mark[9][9],n,m,mins,si,sj;
8
9 //方向数组
10 int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
11
12 struct node
13 {
14 //time 剩余时间;cnt 已花时间
15 int x,y,time,cnt;
16 };
17
18 node f;
19
20 void bfs()
21 {
22 f.x=si;
23 f.y=sj;
24 //已花的时间为0,而剩余的时间为6
25 f.cnt=0;
26 f.time=6;
27 queue<node> q;
28 q.push(f);
29 //这里标注第一个点的所剩的时间
30 mark[si][sj]=6;
31 //如果队列整个空了,则退出
32 while(!q.empty())
33 {
34 node t=q.front();
35 q.pop();
36 if(map[t.x][t.y]==3)
37 {
38 //找到终点了,如果还剩余时间的话,将已经花费的时间输出
39 if(t.time>0)
40 {
41 mins=t.cnt;
42 return;
43 }
44 else continue;
45 }
46 //如果踩到了重置时间的机关,则重置时间,并标记当前位置的时间
47 if(map[t.x][t.y]==4)
48 {
49 t.time=6;
50 mark[t.x][t.y]=6;
51 }
52 for(int k=0;k<4;k++)
53 {
54 //定义一个NEXT结点,这个在前面的吴昊系列已经阐述过了
55 node b;
56 b.x=t.x+dir[k][0];
57 b.y=t.y+dir[k][1];
58 //将已经花费的时间++,而剩余的时间--
59 b.cnt=t.cnt+1;
60 b.time=t.time-1;
61 /*
62 入队的条件,这里有如下一些条件:
63 (1)首先,必须在迷宫的范围之内
64 (2)这个位置不是一堵墙
65 (3)目前还存在剩余时间
66 (4)这个位置标识的最小需要时间必须小于实际的剩余时间(这样才能起到不断优化的作用),由此能不能就判断出是最小值呢?不一定,所以这里也置疑吧!
67 */
68 if(b.x<=n&&b.x>0&&b.y<=m&&b.y>0&&map[b.x][b.y]!=0&&t.time>0&&mark[b.x][b.y]<b.time)
69 {
70 mark[b.x][b.y]=b.time;
71 q.push(b);
72 }
73 }
74 }
75 }
76
77 int main()
78 {
79 int t;
80 //样例的总数
81 cin>>t;
82 while(t--)
83 {
84 //地图的长与宽
85 cin>>n>>m;
86 for(int i=1;i<=n;i++)
87 {
88 for(int j=1;j<=m;j++)
89 {
90 //将地图中的元素进行分类
91 cin>>map[i][j];
92 if(map[i][j]==2)
93 {
94 si=i;
95 sj=j;
96 mark[i][j]=0;
97 }
98 }
99 }
100 //设置一个极大的时间,如果这个时间没有经过任何改动的话,判定出死亡了
101 mins=1000;
102 bfs();
103 if(mins!=1000)
104 cout<<mins<<endl;
105 else cout<<"-1"<<endl;
106 }
107 return 0;
108 }