吴昊品游戏核心算法(新年特别篇) —— 跳格子游戏(DFS+DP)(HDOJ 1978)
“跳格子游戏”应该包括一大类游戏的,现在给出的一种应该算是“实心”的跳格子游戏吧,也就是你可以选择向左走或者向右走,每次走了之后都会触发一系列事 件(这样的游戏有很多,比较简单的一种就是每走到一个格子上面就可以获得一部分积分,在走到终点的时候,需要将获得的积分尽量扩大),你需要选择一种最优 的策略,来让自己获得的利益最大。另外一种属于“空心”的跳格子游戏,类似于“大富翁”,“飞行棋”等等,需要几个人轮流投掷色子,在一个空心的圆环上面 跳格子,地图上的每个格子都会触发一个类似的事件,以此来进行游戏——如图所示的大富翁全地图。我们先看“实心”的跳格子,后面再来看“空心”的跳格子。
(如图所示,此乃简易的实心跳格子游戏)
(如图所示,此乃空心的跳格子游戏)
现在我们来解决实心的部分,游戏的规则如下:
1.机器人一开始在棋盘的起始点并有起始点所标有的能量。
2.机器人只能向右或者向下走,并且每走一步消耗一单位能量。
3.机器人不能在原地停留。
4.当机器人选择了一条可行路径后,当他走到这条路径的终点时,他将只有终点所标记的能量。
(Source:HDOJ 1978)输入整个棋盘,输出需要对10000取模。值得注意的一点是,这里不是在计算最优值,而是要计算所有可能的路线,所以,在使用DP存储以前的路线的时候,要全部保留,不能做一些舍入。
1 /*
2 Highlights:
3 (1)深搜时,由于只能往右或者下方向走,所以加上了i<=step和i+j<=step的条件
4 (2)不要留到最后取模,这样会出现溢出的危险
5 (3)利用sum[x][y]存储一些中间值
6 (4)初始化的时候,将所有的格子的可能步数调节到"不可能"的程度
7 */
8 #include<stdio.h>
9 #include<stdio.h>
10 #include<iostream>
11 using namespace std;
12
13 //常量,N代表行数,M代表列数
14 const int N=101,M=101;
15 //利用grid二维数组定义整个地图
16 int grid[N][M];
17 int sum[N][M]; //以(i,j)为起点到(n,m)的路的条数
18 int n,m;
19
20 //深搜,根据能量值调节搜索的深度
21 int dfs(int x,int y)
22 {
23 if(x==n&&y==m)
24 return 1; //(n,m)到(n,m)条数为1
25 if(sum[x][y]!=-1)
26 return sum[x][y]; //如果曾经访问过,返回记忆中的内容
27 int step=grid[x][y];
28 int num=0; //能量值,即可以走的步数
29 //这里,由于只能往右或者下方向走,所以加上了i<=step和i+j<=step的条件
30 for(int i=0;i<=step;i++)
31 for(int j=0;i+j<=step;j++)
32 {
33 if(!(i==0&&j==0)&&x+i<=n&&y+j<=m)
34 {
35 //i=0,j=0,说明没有走动
36 num+=dfs(x+i,y+j);
37 //及时取模,防止数据溢出
38 num%=10000;
39 }
40 }
41 sum[x][y]=num; //记忆
42 return num;
43 }
44
45 int main()
46 {
47 int t,i,x,k,j,v;
48 //C++的输入输出和C的输入输出混到一起用了!!!
49 cin>>t;
50 while(t--)
51 {
52 scanf("%d%d",&n,&m);
53 for(i=1;i<=n;i++)
54 for(j=1;j<=m;j++)
55 scanf("%d",&grid[i][j]);
56 memset(sum,-1,sizeof(sum)); //初始化,将每一个的数字调节到"无限或者至少是在这个游戏中最可能的小"
57 printf("%d\n",dfs(1,1)); //从(1,1)走到(n,m)的值
58 }
59 return 0;
60 }
61
62
2 Highlights:
3 (1)深搜时,由于只能往右或者下方向走,所以加上了i<=step和i+j<=step的条件
4 (2)不要留到最后取模,这样会出现溢出的危险
5 (3)利用sum[x][y]存储一些中间值
6 (4)初始化的时候,将所有的格子的可能步数调节到"不可能"的程度
7 */
8 #include<stdio.h>
9 #include<stdio.h>
10 #include<iostream>
11 using namespace std;
12
13 //常量,N代表行数,M代表列数
14 const int N=101,M=101;
15 //利用grid二维数组定义整个地图
16 int grid[N][M];
17 int sum[N][M]; //以(i,j)为起点到(n,m)的路的条数
18 int n,m;
19
20 //深搜,根据能量值调节搜索的深度
21 int dfs(int x,int y)
22 {
23 if(x==n&&y==m)
24 return 1; //(n,m)到(n,m)条数为1
25 if(sum[x][y]!=-1)
26 return sum[x][y]; //如果曾经访问过,返回记忆中的内容
27 int step=grid[x][y];
28 int num=0; //能量值,即可以走的步数
29 //这里,由于只能往右或者下方向走,所以加上了i<=step和i+j<=step的条件
30 for(int i=0;i<=step;i++)
31 for(int j=0;i+j<=step;j++)
32 {
33 if(!(i==0&&j==0)&&x+i<=n&&y+j<=m)
34 {
35 //i=0,j=0,说明没有走动
36 num+=dfs(x+i,y+j);
37 //及时取模,防止数据溢出
38 num%=10000;
39 }
40 }
41 sum[x][y]=num; //记忆
42 return num;
43 }
44
45 int main()
46 {
47 int t,i,x,k,j,v;
48 //C++的输入输出和C的输入输出混到一起用了!!!
49 cin>>t;
50 while(t--)
51 {
52 scanf("%d%d",&n,&m);
53 for(i=1;i<=n;i++)
54 for(j=1;j<=m;j++)
55 scanf("%d",&grid[i][j]);
56 memset(sum,-1,sizeof(sum)); //初始化,将每一个的数字调节到"无限或者至少是在这个游戏中最可能的小"
57 printf("%d\n",dfs(1,1)); //从(1,1)走到(n,m)的值
58 }
59 return 0;
60 }
61
62