1、题目
有一类问题总称为“随机漫步”(Random Walk)问题,这类问题长久以来吸引着数学界的兴趣。所有这些问题即使是最简单的解决起来也是极其困难的。而且它们在很大程度上还远没有得到解决。一个这样的问题可以描述为:
在矩形的房间里,铺有n×m块瓷砖,现将一只(醉酒的)蟑螂放在地板中间一个指定方格里。蟑螂随机地从一块瓷砖“漫步”到另一块瓷砖(可能是在找一片阿司匹林)。假设它可能从其所在的瓷砖移动到其周围八块瓷砖中的任何一个(除非碰到墙壁),那么它把每一块瓷砖都至少接触一次将花费多长时间?
虽然这个问题可能很难用纯粹的概率技术来解决,但是使用计算机的话却十分容易。使用计算机解决此问题的技术称为“模拟”。这种技术广泛应用于工业中,用来预测运输流量,存货控制等等。该问题可以采用如下方式进行模拟:
用一个n×m的数组作为计数器来表示蟑螂到达每一块瓷砖的次数,每个数组单元的初始化均置为零。蟑螂在地板上的位置用坐标(currentR,currentC)表示。蟑螂的八种可能移动用在位置(NextR = currentR + imove[k],NextC = currentC + jmove[k])的瓷砖表示,其中0≤k≤7,并且
imove[0] = -1; jmove[0] = 1; //东北方
imove[1] = 0; jmove[1] = 1; //正东方
imove[2] = 1; jmove[2] = 1; //东南方
imove[3] = 1; jmove[3] = 0; //正南方
imove[4] = 1; jmove[4] = -1; //西南方
imove[5] = 0; jmove[5] = -1; //正西方
imove[6] = -1; jmove[6] = -1; //西北方
imove[7] = -1; jmove[7] = 1; //正北方
蟑螂向其相邻的八个方格的随机漫步通过产生一个随机数值k(0≤k≤7)来模拟。当然,蟑螂不能爬出房间外,所以应该去掉通往墙壁的坐标并形成一个新的随机组合。蟑螂每次进入一个方格,该方格的计数器就增加1,从而计数器的一个非零元素就表示蟑螂到达对应方格的次数。每当一个方格被至少进入一次时,试验就完成了。
2、条件
程序必须满足:
①能够处理所有的n和m值, n和m满足:2<n≤40,2≤m≤20;
②能够对“n = 15,m = 15,起始点为(10,10)”和“n = 39,m = 19,起始点为(1,1)”进行实验。
③具有迭代限制,即实验过程中蟑螂进入方块的最大次数为MAX =50000时,程序能够终止。
3、输出
对于每次试验,打印:
①蟑螂进行的合法移动的总次数。
②最终的计数器数组,显示出漫步的“密度”,即输出在实验中每一块瓷砖被接经过的次数。
4、源程序
#include <iostream> #include <cstdlib> #include <ctime> using namespace std; int const MAX_LENGTH = 100; int Random(int m,int n) //指定范围内随机数 { int pos,dis; if(m == n) //表示范围内只有一个数字 return m; else if(m > n) //表示取区间[m,n]内的数字 { pos = n; dis = m - n + 1; return rand() % dis + pos; } else //表示取区间[n,m]内的数字 { pos = m; dis = n - m + 1; return rand() % dis + pos; } } int rmove[8],cmove[8]; //移动方位数组 void InitMove(int* imove,int* jmove) //初始化移动方位数组 { imove[0] = -1; jmove[0] = 1; //东北方 imove[1] = 0; jmove[1] = 1; //正东方 imove[2] = 1; jmove[2] = 1; //东南方 imove[3] = 1; jmove[3] = 0; //正南方 imove[4] = 1; jmove[4] = -1; //西南方 imove[5] = 0; jmove[5] = -1; //正西方 imove[6] = -1; jmove[6] = -1; //西北方 imove[7] = -1; jmove[7] = 1; //正北方 } bool judgewalk(int* mark[],int n,int m) //判断是否访问完所有瓷砖 { for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) { if(!mark[i][j]) //如果有一个没访问完的瓷砖,则退出 return false; } } return true; } void printwalk(int* mark[],int n,int m) //打印所有瓷砖访问次数 { for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) { cout << mark[i][j] << " "; } cout << endl; } } void randomwalk(int** mark,int n,int m) //随机漫步 { srand((int)time(NULL)); //根据时间产生相应种子值 InitMove(rmove,cmove); //初始化移动方位数组 int currentR = Random(0,n - 1); //现在所在行 int currentC = Random(0,m - 1); //现在所在列 mark[currentR][currentC]++; int NextR,NextC; //下一位置所在行,下一位置所在列 int num = 0; //移动次数 while(true) { int moving = Random(0,7); //随机产生移动方向 NextR = currentR + rmove[moving]; //下一位置所在行 NextC = currentC + cmove[moving]; //下一位置所在列 while(NextR < 0 || NextC < 0 || NextR >=n || NextC >= m) //当碰到墙壁时 { moving = Random(0,7); //随机产生移动方向 NextR = currentR + rmove[moving]; //下一位置所在行 NextC = currentC + cmove[moving]; //下一位置所在列 } mark[NextR][NextC]++; //访问+1 currentR = NextR; currentC = NextC; //下一位置等于当前位置 num++; if(judgewalk(mark,n,m)) //判断是否访问完所有瓷砖 { cout << "Total move step:" << num << endl; //打印总步数 printwalk(mark,n,m); //打印所有瓷砖访问次数 return; } if(num > 50000000) //超出访问上限次数 { cout << "Cockroach don't visit all Tile." << endl; cout << "Total move step:" << num << endl; //打印总步数 printwalk(mark,n,m); return; } } } int main() { int *mark[MAX_LENGTH]; //指针数组 for(int i = 0; i < MAX_LENGTH; i++) //动态分配 mark[i] = new int[MAX_LENGTH]; for(int i = 0; i < MAX_LENGTH; i++) //初始化 for(int j = 0; j < MAX_LENGTH;j++) mark[i][j] = 0; int n,m; //行列 cin >> n >> m; randomwalk(mark,n,m); for(int i = 0; i < MAX_LENGTH; i++) //释放空间 delete[] mark[i]; return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。