吴昊品游戏核心算法 Round 11 (增刊) —— 捡花生游戏AI(毫无理性的贪心)(POJ 2950)
这个游戏非常简单,但非常有趣,所以,我在这里不作为Round 12,而将其独立出来,作为一个增刊来放送。这是一款比较老式的游戏了,我曾经在某次过年的时候,在NOKIA的手机上玩过,当时是塞班的系统,画质不怎么样,但是非常有趣。
玩法简介:
一个直观的想法:
将整个花生地作为一个二维的整型数组,没有花生的地方标注0而有花生的地方标注花生的数目。一个比较直观的想法就是自变量为时间t和这个二维数组,因变量 为最多可以获得花生数目的函数,当然,这个做法直观,而且可以确定这个函数是存在的(因为满足一一对应的关系),但问题是你建立地出来咩?
放弃直观的想法,我们开始推理:
有一种贪心的想法,如果我们一开始就瞄准花生最多的位置,然后再逐渐瞄准花生比较多的位置,依此类推,可否达到最优解呢?显然,我们每次都是尽量地局部最优,但是,局部最优是并不一定可以保证全局最优的,那么,我们不妨简单论证一下我们刚才的想法。
如果我们一开始放弃花生数目最多的位置而找花生次多的位置,会发生什么?
假设存在这种情况,那么,我们不能采数目最多花生的理由是什么?(1)时间不够(2)可能会落下在附近的不是次多数目的花生。我们不妨设想一种情况,假设 数目最多花生的旁边有5颗花生,而如果我们要去采更远处的10颗花生的话,等于还要“绕回来”,所以那位老人所说的“每次采数目最多的花生”的贪心策略是 不理智的。但是,由于问题要求我们用老人所说的方式去做,我们就只好将老人的吩咐作为AI咯~这个AI比较弱智,觉得。
动态规划:
考虑所有的可能性,并且将一些中间值进行存储,是AI最准备而时间效率尽量高的做法了,贪心简便而迅速,但如果不严格地证明的话,经常会有问题。
Solve:
2 #include<stdlib.h>
3 #include<memory.h>
4 #include<math.h>
5
6 //定义一个"花生地"的最大长度和宽度(这里上限是50*50)
7 #define MAX_NUM 55
8
9 int T,M,N,K;
10 int aField[MAX_NUM][MAX_NUM];
11
12 int main()
13 {
14 //读入对应的案例
15 scanf("%d",&T);
16 for(int t=0;t<T;t++)
17 {
18 scanf("%d%d%d",&M,&N,&K);
19 //这里为了方便描述,将数组的开始标志设为1
20 for(int m=1;m<=M;m++)
21 {
22 for(int n=1;n<=N;n++)
23 {
24 scanf("%d",&aField[m][n]);
25 }
26 }
27 //采摘到的花生总数,这里是一个不错的变量命名
28 int nTotalPeanuts=0;
29 //已经过去的时间
30 int nTotalTime=0;
31 //设置横纵坐标的初始值,横坐标是确定的,而纵坐标不确定
32 int nCuri=0;
33 int nCurj;
34 //直到时间耗尽位置
35 while(nTotalTime<K)
36 {
37 //找到最大花生的数目和所在位置
38 int nMax=0,nMaxi,nMaxj;
39 for(int i=1;i<=M;i++)
40 {
41 for(int j=1;j<=N;j++)
42 {
43 if(nMax<aField[i][j])
44 {
45 nMax=aField[i][j];
46 nMaxi=i;
47 nMaxj=j;
48 }
49 }
50 }
51 //这里一个剪枝,如果地里已经没有花生了,则可以退出
52 if(nMax==0)
53 break;
54 if(nCuri==0)
55 {
56 //如果我们是在初始阶段的话,那么一个贪心的想法,我们先看看能否走到花生最多的地方
57 nCurj=nMaxj;
58 }
59 //这里的判断如下,其中的1是采花生的时间,而每次都要确保有时间回来
60 if(nTotalTime+nMaxi+1+abs(nMaxi-nCuri)+abs(nMaxj-nCurj)<=K)
61 {
62 //追加时间
63 nTotalTime+=1+abs(nMaxi-nCuri)+abs(nMaxj-nCurj);
64 //走到新的位置
65 nCuri=nMaxi;
66 nCurj=nMaxj;
67 //追加采到的花生的总数
68 nTotalPeanuts+=aField[nMaxi][nMaxj];
69 //采走花生
70 aField[nMaxi][nMaxj]=0;
71 }
72 else break;
73 }
74 printf("%d\n",nTotalPeanuts);
75 }
76 return 0;
77 }