寻找迷宫出口的题目好像有很多,解法好像也很多,在这里我只是说说自己发现的一种解法。至于到底有没有人也是这样做的,说不准,方正我是没看过。那么请往下看。
首先,为了模拟迷宫,需要自己设置哪里是墙壁,哪里是通道,这个我采用01表示法来做:
1110000000000000
0010000000000000
0010001111111100
0010001000000100
0010001000000100
0010001111110100
0010000000010100
0011111111110111
0010000000010011
0010000000010010
0010000000010010
0010000000010010
0010000000010010
0010000000010010
0010000000010010
0011111111101111
以上一共是16*16个数字,0代表墙壁,1代表通道。到时候只需要读取文件,就可以模拟迷宫了。
(在我的程序中,使用二维数组来表示坐标,0表示墙壁,-1表示通道而且还没有人路过,1,2,3等表示从起点到该位置的步数,起点设置为1)
原理:其实原理很简单。如图
阴影表示墙壁,1是起点。从起点开始,周围四格“可通”的话它的数值就在原来格数的基础上+1。这里“可通”的概念是,前进的那格既不是墙壁,也不是原方向,也不是已经走过的路径(对于后两者,目标格的数字会比当前格的数字小)。就这样1找到了2(两个),其中一个2找到了前进方向3…….图中有两个7,其中绕远路的显然不是我们希望的。
通过一步一步MarkTheWay(column,row) 递归,直到无路(每个分支都没有可以前进的格)可走了,结束寻路过程。
这里有程序的输出:
1是起点,51是出口。在初始化的时候,出口被设置为-1,当出口不是-1时,就说明有路径可以到达出口。否则说明不能(如下图)。
以上过程只是验证能否到达出口以及找出路径数目和最短步数,还没有指出怎么走。这样吧,从上面成功的路中可以看出,这样从出口处沿着数字递减的方向往回走,就一定能够找到起点。函数FindShortWay如下:
private void FindShortWay()
{
int column = x2;
int row = y2;
int current = migong[column, row];
while ((current = migong[column, row])!=1)
{
Console.Write(FormatPoint(column, row)+" -> ");
if (CanBack(column + 1, row,current))
{
column+=1;
continue;
}
if (CanBack(column - 1, row, current))
{
column -= 1;
continue;
}
if (CanBack(column, row + 1, current))
{
row += 1;
continue;
}
if (CanBack(column, row - 1, current))
{
row -= 1;
continue;
}
}
虽说最短路可能是多条,但是只要找到一条就足够了(我偷懒)。
//源代码附上。献丑了。
namespace Test
{
class FindMiGong
{
static void Main(string[] args)
{
FindWay findway = new FindWay();
findway.GetTheWay();//执行
Console.ReadLine();
}
}
class FindWay
{
private const int COUNT = 16;
private int x1 = 0; //起点x坐标
private int y1 = 0; //起点y坐标
private int x2 = 15; //出口x坐标
private int y2 = 15; //出口y坐标
public int WayCount { get; set; } //通道数
public int ShortestWay = -1;//最短步数
private int[,] migong=new int[COUNT,COUNT];
private void InitMigong(string datafile) //初始化
{
try
{
using (FileStream afile = new FileStream(datafile, FileMode.Open))
{
using (StreamReader reader = new StreamReader(afile))
{
string line = string.Empty;
for (int column = 0; column < COUNT; column++)
{
line = reader.ReadLine();
char[] chars = line.ToArray();
for (int row = 0; row < COUNT; row++)
{
migong[column, row] = int.Parse(chars[row].ToString());
}
}
}
for (int column = 0; column < COUNT; column++)
{
for (int row = 0; row < COUNT; row++)
{
if (migong[column,row] == 1)
migong[column, row] = -1; //0表示墙壁,-1表示还无人路过。
}
}
migong[x1, y1] = 1; //初始化起点
}
}
catch{throw;}
}
public void GetTheWay()
{
//0 is blocked,-1 is the init data;
string datafile = @"C:\Users\Administrator\Desktop\data.txt";
InitMigong(datafile);
MarkTheWay(x1,y1); //最主要的步骤,详细内容往下看
if (IsArrived()) //是否可以达到出口
{
Console.WriteLine("shortest way is:"+ShortestWay);
Console.WriteLine("way count:" + WayCount);
FindShortWay();
}
else
{
Console.WriteLine("can't exit the migong ");
}
OutPut();
}
private bool IsArrived()
{
return !(migong[x2, y2] == -1);
}
private void MarkTheWay(int column,int row)
{
int current = migong[column, row];
int next = current + 1;
if (CanGo(column+1, row,current))
{
migong[column + 1, row] = next;
MarkTheWay(column + 1, row);
}
if (CanGo(column-1, row,current))
{
migong[column - 1, row] = next;
MarkTheWay(column - 1, row);
}
if (CanGo(column, row+1,current))
{
migong[column, row + 1] = next;
MarkTheWay(column, row + 1);
}
if (CanGo(column, row-1,current))
{
migong[column, row - 1] = next;
MarkTheWay(column, row - 1);
}
}
private bool CanGo(int column, int row,int lastNumber)
{
if (column < 0 || column > COUNT - 1 || row < 0 || row > COUNT - 1)
return false;
int current = migong[column, row];
if (current == 0)
return false;
if (current != -1 && current < lastNumber)
return false;
HaveArrived(column, row,lastNumber); //到达出口路径数+1,统计最短的情况
return true;
}
private void HaveArrived(int column, int row,int lastNumber)
{
if (column == x2 && row == y2)
{
WayCount++;
if (ShortestWay < 0)
{
ShortestWay = lastNumber;
}
else
{
ShortestWay = lastNumber < ShortestWay ? lastNumber : ShortestWay;
}
}
return;
}
public void OutPut()
{
for (int column = 0; column < COUNT; column++)
{
for (int row = 0; row < COUNT; row++)
{
Console.Write(migong[column, row].ToString().PadRight(3));
}
Console.Write('\n');
}
}
private bool CanBack(int column, int row, int lastNumber)
{
if (column < 0 || column > COUNT - 1 || row < 0 || row > COUNT - 1)
return false;
int current = migong[column, row];
if (current != lastNumber - 1)
return false;
return true;
}
private string FormatPoint(int column, int row)
{
return "(" + column + "," + row + ")";
}
private void FindShortWay()
{
int column = x2;
int row = y2;
int current = migong[column, row];
while ((current = migong[column, row])!=1)
{
Console.Write(FormatPoint(column, row)+" -> ");
if (CanBack(column + 1, row,current))
{
column+=1;
continue;
}
if (CanBack(column - 1, row, current))
{
column -= 1;
continue;
}
if (CanBack(column, row + 1, current))
{
row += 1;
continue;
}
if (CanBack(column, row - 1, current))
{
row -= 1;
continue;
}
}
Console.Write(FormatPoint(column, row));
Console.WriteLine();
}
}
}