概述
笔者最初接触到分形迷宫是在某日浏览了 matrix67 的一篇博客“大开眼界:世上最无敌的迷宫当数‘分形迷宫’”(网址 http://www.matrix67.com/blog/archives/74 ),当时了解到利用递归定义迷宫的方式实在是新颖,不由得来了兴趣。当时网络上也没有太多关于这方面的资料,而博客中给出的例子似乎又不像是普通的人脑可以模拟出来的,于是便产生了编程解决的想法。不过由于杂事过多,为准备省赛使得这个想法荒废了很长时间,直到丙申年寒假才开始编,中间又因省选停了一段时间,直到丙申年国庆才基本编完。不过,令笔者欣慰的是,笔者的程序成功地将博客上给出的例子解了出来,运行并没有耗费太多的时间。
在本文接下来的论述里,笔者将首先给出分形迷宫的定义和图与数据的转化;接着将给出一种浅显的算法和几个或许未经证实但很大可能有用的优化;然后笔者将贴出自己的代码,从代码中可以一览笔者所用算法的全貌;最后笔者将对网络上现有的屈指可数的实例汇总并给出可能的最优解。对原问题的解决方法不太感兴趣的读者可以忽略算法及优化和代码部分。
由于水平所限,错误之处在所难免,在此也恳请广大读者对本文中的错误之处加以指正,笔者不胜感激。
定义
顾名思义,分形迷宫是一个迷宫,其形式大多以电路的形式给出,移动单位为单个电子,其要求不外乎迷宫的一般要求,查询一条路径从给定起点到给定终点,并使路径最优。然而,和一般迷宫不同的是,分形迷宫之所以称之为分形,其原因在于迷宫中存在一个或多个形式为自身的子迷宫,即可以通过迭代自身的方法使迷宫无限次的加深下去,其编号用大写英文字母增序表示。从这个意义上来说,这个迷宫的规模是无限的。相应的,我们对于路径的要求也做了一些更改。
为了解释的方便起见,我们根据一个分形迷宫建一棵多叉树,使得每个顶点都有相同数目的子节点,且满足任意一个节点都可以通过迭代自身的方式进入其子节点(此时电子由子迷宫外缘移动到子迷宫内缘),而且每一个节点都可以通过退出当层迭代的方式返回其父节点(此时电子由迷宫内缘移动到迷宫外缘,在这种情况下该节点不能为根)。我们定义根节点的深度为 0,则相应的,这个多叉树上的每一个节点都有相应的深度。对于一个符合要求的路径,其最大深度必须是有限的。
满足以上条件的从起点到终点的路径也许有多条,而我们在大多数情况下关心的只是其中最优的一条。关于“最优”的解释方法有两种,一种是路径的最大深度最优,一种是路径的长度最优。考虑到电路的长度不方便计算以及计算机的存储规模,我们将采用最大深度最小的路径作为最优解。在本文接下来的论述中,若无特殊说明,则本文剩余部分所叙述的最优解按照本段的定义理解。
转化
很明显,原题是一个图论问题。在当代,大多数计算机更偏好处理数据而不是图,所以将图用其等价的数据来描述是必要的。在这里,笔者将给出把图转化为其等价数据的一种形式,即给出将图转化为计算机可以识别的数据且不损失原图有效信息的一个约定,并对原问题做进一步的分析。
对于一个分形迷宫,我们将图上的有效信息分为点和边。对于一个点,它满足其位置必在迷宫边缘或子迷宫边缘且与边连接。相应的,一条边可以连接两个或更多个点。注意,在这里,边的定义允许连接两个以上的点,这似乎与传统意义上的边的定义不符。但是,我们可以这样思考,假设图中存在一些游离于迷宫边缘和子迷宫边缘的点,它们连接着三条或以上的边,则迷宫上的所有边都可以只连接两个点。这些游离点既不能访问其树上子节点的状态,又不能返回其树上父节点的状态。这些游离点毫无疑问将会占用大量的空间。现在,为了方便起见,我们将这些游离点删去,将所有与同一个游离点相连的点都由间接连接改为直接连接。这种变换很明显是等价的。
我们将每个点在迷宫图上的位置都用一个二元组 (module, unit) 来表示。其中 module 表示点在图上的模块数,0 表示在迷宫边缘,1 表示在子迷宫 A 的边缘,2 表示在子迷宫 B 的边缘,以此类推。而 unit 确切表示点在任意模块中的确切位置,我们从左上角开始用阿拉伯数字从 1 增序顺时针编号。特别的,我们用 (0, 0) 表示阴极,用 (1, 0) 表示阳极。这样,图上的每个点都有其唯一表示方法。
对于一个图的数据形式输入文件,其第一行给出两个正整数 n 和 m,其中 n 表示子迷宫数,m 表示边数。接下来 m 行,每行第一个正整数 t,表示这条边所连点数,接下来 2 * t 个正整数,表示由二元组所描述的 t 个点的确切位置。输入需保证任何一个点不重复出现。
算法
显然的,这个问题最直接的解决方法是搜索。考虑到起始状态和终止状态已知,且最优解的限定条件为路径的最大深度最小,我们可以使用 迭代加深双向广度优先搜索 的算法来优化时间复杂度。这个算法的主体是广度优先搜索,加之以迭代加深和双向的时间优化。
迭代加深的基本思想是,我们先设定一个深度限定最大值,使得我们搜索的路径的最大深度不超过限定值,当无法找到路径时调高限定值继续搜索。如此一来,我们可以保证搜索出的路径必然是当前状态下的最优解。关于双向搜索的好处是显而易见的。由于起止状态已知,同时向中间搜索便能省去很多不必要的空间。
优化
但是,面对一些规模庞大的数据,即使运用以上方法仍不能将时间和空间压缩到理想的范围之内。在这里,笔者将给出几种可能的优化:
哈希 :为了记录当前进入的节点,我们可以用一个整型变量来表示。可是,当深度变大后,这个方法不再适用了,我们将必须使用字符型数组储存。于是,为了避免重复状态的搜索和快速找到状态所对应的搜索队列中的位置,空间的优化变得非常棘手了。哈希在理论上可以很好地解决这个问题,但其可行性有待验证。
内存池 :为了用字符数组记录当前节点所对应的状态,一种方法是对搜索队列中的每一个单元开字符数组。毫无疑问,这种方法浪费了大量空间。另一种方法是开一个字符数组的内存池,我们每次只需记录下当前状态字符串在内存池中的起始位置和长度,每次将新的字符串压入内存池中,即可完成空间的优化。
持久化字符序列 :基于以下原理:p 个基本元素排列成长度为 n 的状态共有 p^n 种,我们可以找到一个长度为 p^n + n - 1 的元素序列使得这 p^n 种不同状态对应这个序列的所有长度为 n 的子字符串。这种算法的时间复杂度在我们可以接受的范围之内。不过看来,这似乎增加了空间的开支,而且只对稠密图有明显的效果。与哈希配合应该可以解决其空间上的问题。关于持久化字符序列的实现方法等更多问题本文将不再做过多的论述。
代码
笔者的程序采用文件输入输出的形式。笔者的代码只采用了内存池的方法优化,但这已足够解决大多数问题了。值得一提的是,笔者的代码中还加入了合法输入判定。
由于代码过于复杂,难免有疏漏不足之处,欢迎读者指正。
#include"stdio.h"
#include"string.h"
#define MAX_CHARSTR (0x3FFFF)
#define MAX_CONNECTION (0xF)
#define MAX_FLOOR (0xF)
#define MAX_MODULE (0xF)
#define MAX_OPT (0x3FFF)
#define MAX_QUEUE (0x1FFFF)
#define MAX_UNIT (0x3F)
char FMcharstr[MAX_CHARSTR],FMQtemp0[MAX_FLOOR],FMQtemp1[MAX_FLOOR];
int FMstrtop,line[MAX_MODULE][MAX_UNIT],opt0[MAX_MODULE][MAX_UNIT][MAX_OPT],opt1[MAX_MODULE][MAX_UNIT][MAX_OPT];
struct FRACTALMAZE_UNIT
{
int module,unit;
};
struct FRACTALMAZE_MAZE
{
int total;
FRACTALMAZE_UNIT to[MAX_CONNECTION];
}FMaze[MAX_MODULE][MAX_UNIT],temp;
struct FRACTALMAZE_QUEUE
{
int first,floor,power,prev;
FRACTALMAZE_UNIT now;
}FMQueue0[MAX_QUEUE],FMQueue1[MAX_QUEUE];
void changeprev(int now)
{
if(FMQueue0[now].prev>0)
changeprev(FMQueue0[now].prev);
FMQueue0[FMQueue0[now].prev].prev=now;
}
int main()
{
freopen("FractalMaze.in","r",stdin);
freopen("FractalMaze.out","w",stdout);
int flag,front0,front1,m,n,rear0,rear1;
scanf("%d %d",&n,&m);
memset(line,0,sizeof(line));
while(m--)
{
scanf("%d",&temp.total);
for(int i=0;i<temp.total;i++)
scanf("%d %d",&temp.to[i].module,&temp.to[i].unit),
FMaze[temp.to[i].module][temp.to[i].unit].total=temp.total-1,
line[temp.to[i].module][temp.to[i].unit]++;
for(int i=0;i<temp.total;i++)
{
flag=0;
for(int j=0;j<temp.total;j++)
if(i!=j)
FMaze[temp.to[i].module][temp.to[i].unit].to[j+flag]=temp.to[j];
else
flag=-1;
if(line[temp.to[i].module][temp.to[i].unit]>1)
{
printf("Input %d %d is wrong.",temp.to[i].module,temp.to[i].unit);
return 0;
}
}
}
/*for(int i=0;i<=3;i++)
{
for(int j=1;j<=16;j++)
{
printf("%d",FMaze[i][j].total);
for(int k=0;k<FMaze[i][j].total;k++)
printf(" %d %d",FMaze[i][j].to[k].module,FMaze[i][j].to[k].unit);
printf("\n");
}
printf("\n");
}
printf("%d",FMaze[0][0].total);
for(int i=0;i<FMaze[0][0].total;i++)
printf(" %d %d",FMaze[0][0].to[i].module,FMaze[0][0].to[i].unit);
printf("\n%d",FMaze[1][0].total);
for(int i=0;i<FMaze[1][0].total;i++)
printf(" %d %d",FMaze[1][0].to[i].module,FMaze[1][0].to[i].unit);
printf("\n\n");*/
++n;
front0=front1=0;
rear0=rear1=1;
FMQueue0[0].first=FMQueue1[0].first=0;
FMQueue0[0].floor=FMQueue1[0].floor=0;
FMQueue0[0].now.module=0,FMQueue1[0].now.module=1;
FMQueue0[0].now.unit=FMQueue1[0].now.unit=0;
FMQueue0[0].power=FMQueue1[0].power=0;
FMQueue0[0].prev=FMQueue1[0].prev=-1;
FMstrtop=0;
memset(FMcharstr,'\0',sizeof(FMcharstr));
memset(opt0,-1,sizeof(opt0));
memset(opt1,-1,sizeof(opt1));
opt0[0][0][0]=opt1[1][0][0]=0;
for(int f=1;f<MAX_FLOOR&&flag==-1;f++)
{
flag=-1;
for(int i=0;i<front0;i++)
{
strncpy(FMQtemp0,FMcharstr+FMQueue0[i].first,FMQueue0[i].floor);
FMQtemp0[FMQueue0[i].floor]=FMQueue0[i].now.module+64;
FMQtemp0[FMQueue0[i].floor+1]='\0';
if(FMQueue0[i].now.module>0&&FMQueue0[i].now.unit>0
&&opt0[0][FMQueue0[i].now.unit][FMQueue0[i].power*n+FMQueue0[i].now.module]==-1)
strcpy(FMcharstr+FMstrtop,FMQtemp0),
FMQueue0[rear0].first=FMstrtop,
FMQueue0[rear0].floor=FMQueue0[i].floor+1,
FMQueue0[rear0].now.module=0,
FMQueue0[rear0].now.unit=FMQueue0[i].now.unit,
FMQueue0[rear0].power=FMQueue0[i].power*n+FMQueue0[i].now.module,
FMQueue0[rear0].prev=i,
FMstrtop+=FMQueue0[rear0].floor+1,
flag=opt1[FMQueue0[rear0].now.module][FMQueue0[rear0].now.unit][FMQueue0[rear0].power]>-1?rear0:-1,
//printf("last0: %d %d %d %d %d %d ",rear0,FMQueue0[rear0].now.module,FMQueue0[rear0].now.unit,FMQueue0[rear0].floor,FMQueue0[rear0].power,i),puts(FMcharstr+FMQueue0[rear0].first),
opt0[FMQueue0[rear0].now.module][FMQueue0[rear0].now.unit][FMQueue0[rear0].power]=rear0++;
}
for(int i=0;i<front1;i++)
{
strncpy(FMQtemp1,FMcharstr+FMQueue1[i].first,FMQueue1[i].floor);
FMQtemp1[FMQueue1[i].floor]=FMQueue1[i].now.module+64;
FMQtemp1[FMQueue1[i].floor+1]='\0';
if(FMQueue1[i].now.module>0&&FMQueue1[i].now.unit>0
&&opt1[0][FMQueue1[i].now.unit][FMQueue1[i].power*n+FMQueue1[i].now.module]==-1)
strcpy(FMcharstr+FMstrtop,FMQtemp1),
FMQueue1[rear1].first=FMstrtop,
FMQueue1[rear1].floor=FMQueue1[i].floor+1,
FMQueue1[rear1].now.module=0,
FMQueue1[rear1].now.unit=FMQueue1[i].now.unit,
FMQueue1[rear1].power=FMQueue1[i].power*n+FMQueue1[i].now.module,
FMQueue1[rear1].prev=i,
FMstrtop+=FMQueue1[rear1].floor+1,
flag=opt0[FMQueue1[rear1].now.module][FMQueue1[rear1].now.unit][FMQueue1[rear1].power],
//printf("last1: %d %d %d %d %d %d ",rear1,FMQueue1[rear1].now.module,FMQueue1[rear1].now.unit,FMQueue1[rear1].floor,FMQueue1[rear1].power,i),puts(FMcharstr+FMQueue1[rear1].first),
opt1[FMQueue1[rear1].now.module][FMQueue1[rear1].now.unit][FMQueue1[rear1].power]=rear1++;
}
for(;front0<rear0&&front1<rear1&&flag==-1;front0++,front1++)
{
for(int i=0;i<FMaze[FMQueue0[front0].now.module][FMQueue0[front0].now.unit].total;i++)
if(opt0[FMaze[FMQueue0[front0].now.module][FMQueue0[front0].now.unit].to[i].module][FMaze[FMQueue0[front0].now.module][FMQueue0[front0].now.unit].to[i].unit][FMQueue0[front0].power]==-1)
strncpy(FMcharstr+FMstrtop,FMcharstr+FMQueue0[front0].first,FMQueue0[front0].floor),
FMQueue0[rear0].first=FMstrtop,
FMQueue0[rear0].floor=FMQueue0[front0].floor,
FMQueue0[rear0].now.module=FMaze[FMQueue0[front0].now.module][FMQueue0[front0].now.unit].to[i].module,
FMQueue0[rear0].now.unit=FMaze[FMQueue0[front0].now.module][FMQueue0[front0].now.unit].to[i].unit,
FMQueue0[rear0].power=FMQueue0[front0].power,
FMQueue0[rear0].prev=front0,
FMstrtop+=FMQueue0[rear0].floor+1,
flag=opt1[FMQueue0[rear0].now.module][FMQueue0[rear0].now.unit][FMQueue0[rear0].power]>-1?rear0:-1,
//printf("forfront0: %d %d %d %d %d %d ",rear0,FMQueue0[rear0].now.module,FMQueue0[rear0].now.unit,FMQueue0[rear0].floor,FMQueue0[rear0].power,front0),puts(FMcharstr+FMQueue0[rear0].first),
opt0[FMQueue0[rear0].now.module][FMQueue0[rear0].now.unit][FMQueue0[rear0].power]=rear0++;
strncpy(FMQtemp0,FMcharstr+FMQueue0[front0].first,FMQueue0[front0].floor);
strncpy(FMQtemp1,FMcharstr+FMQueue0[front0].first,FMQueue0[front0].floor);
FMQtemp0[FMQueue0[front0].floor]=FMQueue0[front0].now.module+64;
FMQtemp0[FMQueue0[front0].floor+1]='\0';
if(FMQueue0[front0].floor>0)
FMQtemp1[FMQueue0[front0].floor-1]='\0';
if(FMQueue0[front0].now.module==0&&FMQueue0[front0].floor>0
&&opt0[FMcharstr[FMQueue0[front0].first+FMQueue0[front0].floor-1]-64][FMQueue0[front0].now.unit][FMQueue0[front0].power/n]==-1)
strcpy(FMcharstr+FMstrtop,FMQtemp1),
FMQueue0[rear0].first=FMstrtop,
FMQueue0[rear0].floor=FMQueue0[front0].floor-1,
FMQueue0[rear0].now.module=FMcharstr[FMQueue0[front0].first+FMQueue0[front0].floor-1]-64,
FMQueue0[rear0].now.unit=FMQueue0[front0].now.unit,
FMQueue0[rear0].power=FMQueue0[front0].power/n,
FMQueue0[rear0].prev=front0,
FMstrtop+=FMQueue0[rear0].floor+1,
flag=opt1[FMQueue0[rear0].now.module][FMQueue0[rear0].now.unit][FMQueue0[rear0].power]>-1?rear0:-1,
//printf("minusfront0: %d %d %d %d %d %d ",rear0,FMQueue0[rear0].now.module,FMQueue0[rear0].now.unit,FMQueue0[rear0].floor,FMQueue0[rear0].power,front0),puts(FMcharstr+FMQueue0[rear0].first),
opt0[FMQueue0[rear0].now.module][FMQueue0[rear0].now.unit][FMQueue0[rear0].power]=rear0++;
else if(FMQueue0[front0].now.module>0&&FMQueue0[front0].floor+1<f
&&opt0[0][FMQueue0[front0].now.unit][FMQueue0[front0].power*n+FMQueue0[front0].now.module]==-1)
strcpy(FMcharstr+FMstrtop,FMQtemp0),
FMQueue0[rear0].first=FMstrtop,
FMQueue0[rear0].floor=FMQueue0[front0].floor+1,
FMQueue0[rear0].now.module=0,
FMQueue0[rear0].now.unit=FMQueue0[front0].now.unit,
FMQueue0[rear0].power=FMQueue0[front0].power*n+FMQueue0[front0].now.module,
FMQueue0[rear0].prev=front0,
FMstrtop+=FMQueue0[rear0].floor+1,
flag=opt1[FMQueue0[rear0].now.module][FMQueue0[rear0].now.unit][FMQueue0[rear0].power]>-1?rear0:-1,
//printf("plusfront0: %d %d %d %d %d %d ",rear0,FMQueue0[rear0].now.module,FMQueue0[rear0].now.unit,FMQueue0[rear0].floor,FMQueue0[rear0].power,front0),puts(FMcharstr+FMQueue0[rear0].first),
opt0[FMQueue0[rear0].now.module][FMQueue0[rear0].now.unit][FMQueue0[rear0].power]=rear0++;
for(int i=0;i<FMaze[FMQueue1[front1].now.module][FMQueue1[front1].now.unit].total;i++)
if(opt1[FMaze[FMQueue1[front1].now.module][FMQueue1[front1].now.unit].to[i].module][FMaze[FMQueue1[front1].now.module][FMQueue1[front1].now.unit].to[i].unit][FMQueue1[front1].power]==-1)
strncpy(FMcharstr+FMstrtop,FMcharstr+FMQueue1[front1].first,FMQueue1[front1].floor),
FMQueue1[rear1].first=FMstrtop,
FMQueue1[rear1].floor=FMQueue1[front1].floor,
FMQueue1[rear1].now.module=FMaze[FMQueue1[front1].now.module][FMQueue1[front1].now.unit].to[i].module,
FMQueue1[rear1].now.unit=FMaze[FMQueue1[front1].now.module][FMQueue1[front1].now.unit].to[i].unit,
FMQueue1[rear1].power=FMQueue1[front1].power,
FMQueue1[rear1].prev=front1,
FMstrtop+=FMQueue1[rear1].floor+1,
flag=opt0[FMQueue1[rear1].now.module][FMQueue1[rear1].now.unit][FMQueue1[rear1].power],
//printf("forfront1: %d %d %d %d %d %d ",rear1,FMQueue1[rear1].now.module,FMQueue1[rear1].now.unit,FMQueue1[rear1].floor,FMQueue1[rear1].power,front1),puts(FMcharstr+FMQueue1[rear1].first),
opt1[FMQueue1[rear1].now.module][FMQueue1[rear1].now.unit][FMQueue1[rear1].power]=rear1++;
strncpy(FMQtemp0,FMcharstr+FMQueue1[front1].first,FMQueue1[front1].floor);
strncpy(FMQtemp1,FMcharstr+FMQueue1[front1].first,FMQueue1[front1].floor);
FMQtemp0[FMQueue1[front1].floor]=FMQueue1[front1].now.module+64;
FMQtemp0[FMQueue1[front1].floor+1]='\0';
if(FMQueue1[front1].floor>0)
FMQtemp1[FMQueue1[front1].floor-1]='\0';
if(FMQueue1[front1].now.module==0&&FMQueue1[front1].floor>0
&&opt1[FMcharstr[FMQueue1[front1].first+FMQueue1[front1].floor-1]-64][FMQueue1[front1].now.unit][FMQueue1[front1].power/n]==-1)
strcpy(FMcharstr+FMstrtop,FMQtemp1),
FMQueue1[rear1].first=FMstrtop,
FMQueue1[rear1].floor=FMQueue1[front1].floor-1,
FMQueue1[rear1].now.module=FMcharstr[FMQueue1[front1].first+FMQueue1[front1].floor-1]-64,
FMQueue1[rear1].now.unit=FMQueue1[front1].now.unit,
FMQueue1[rear1].power=FMQueue1[front1].power/n,
FMQueue1[rear1].prev=front1,
FMstrtop+=FMQueue1[rear1].floor+1,
flag=opt0[FMQueue1[rear1].now.module][FMQueue1[rear1].now.unit][FMQueue1[rear1].power],
//printf("minusfront1: %d %d %d %d %d %d ",rear1,FMQueue1[rear1].now.module,FMQueue1[rear1].now.unit,FMQueue1[rear1].floor,FMQueue1[rear1].power,front1),puts(FMcharstr+FMQueue1[rear1].first),
opt1[FMQueue1[rear1].now.module][FMQueue1[rear1].now.unit][FMQueue1[rear1].power]=rear1++;
else if(FMQueue1[front1].now.module>0&&FMQueue1[front1].now.unit>0&&FMQueue1[front1].floor+1<f
&&opt1[0][FMQueue1[front1].now.unit][FMQueue1[front1].power*n+FMQueue1[front1].now.module]==-1)
strcpy(FMcharstr+FMstrtop,FMQtemp0),
FMQueue1[rear1].first=FMstrtop,
FMQueue1[rear1].floor=FMQueue1[front1].floor+1,
FMQueue1[rear1].now.module=0,
FMQueue1[rear1].now.unit=FMQueue1[front1].now.unit,
FMQueue1[rear1].power=FMQueue1[front1].power*n+FMQueue1[front1].now.module,
FMQueue1[rear1].prev=front1,
FMstrtop+=FMQueue1[rear1].floor+1,
flag=opt0[FMQueue1[rear1].now.module][FMQueue1[rear1].now.unit][FMQueue1[rear1].power],
//printf("plusfront1: %d %d %d %d %d %d ",rear1,FMQueue1[rear1].now.module,FMQueue1[rear1].now.unit,FMQueue1[rear1].floor,FMQueue1[rear1].power,front1),puts(FMcharstr+FMQueue1[rear1].first),
opt1[FMQueue1[rear1].now.module][FMQueue1[rear1].now.unit][FMQueue1[rear1].power]=rear1++;
}
//printf("%d %d %d %d %d %d\n\n",f,front0,front1,rear0,rear1,flag);
}
if(flag==-1)
{
printf("No answer");
return 0;
}
//printf("%d\n",flag);
changeprev(flag);
FMQueue0[flag].prev=-1;
for(int i=0;i>-1;i=FMQueue0[i].prev)
printf("%d %d ",FMQueue0[i].now.module,FMQueue0[i].now.unit),puts(FMcharstr+FMQueue0[i].first);
flag=FMQueue1[opt1[FMQueue0[flag].now.module][FMQueue0[flag].now.unit][FMQueue0[flag].power]].prev;
//printf("\n%d\n",flag);
for(int i=flag;i>-1;i=FMQueue1[i].prev)
printf("%d %d ",FMQueue1[i].now.module,FMQueue1[i].now.unit),puts(FMcharstr+FMQueue1[i].first);
/*printf("\n\n0:\n");
for(int i=0;i<rear0;i++)
printf("%d %d %d %d %d %d ",i,FMQueue0[i].now.module,FMQueue0[i].now.unit,FMQueue0[i].floor,FMQueue0[i].power,FMQueue0[i].prev),puts(FMcharstr+FMQueue0[i].first);
printf("\n1:\n");
for(int i=0;i<rear1;i++)
printf("%d %d %d %d %d %d ",i,FMQueue1[i].now.module,FMQueue1[i].now.unit,FMQueue1[i].floor,FMQueue1[i].power,FMQueue1[i].prev),puts(FMcharstr+FMQueue1[i].first);
printf("\n%d\n",FMstrtop);
for(int i=0;i<FMstrtop;i++)
if(FMcharstr[i]=='\0')
printf(" ");
else
printf("%c",FMcharstr[i]);*/
return 0;
}
实例
关于分形迷宫的实例似乎较少,其原因主要由于其构造的复杂性。笔者从网络上找到了一些分形迷宫的实例,在此集中演示并给出它们可能的最优解。
第一个和第二个实例来源于 matrix67,链接在本文第一段已经给出。
FractalMaze1.in | FractalMaze1.out |
---|---|
3 18 2 1 0 3 10 2 0 0 1 12 4 0 1 0 15 0 16 1 1 2 0 2 1 4 5 0 3 0 12 1 5 2 7 3 1 2 0 4 2 1 2 0 5 2 4 2 0 6 2 8 3 0 7 1 3 3 6 4 0 8 0 10 0 13 1 11 2 0 9 2 3 3 0 11 0 14 1 14 2 1 8 2 16 2 1 9 3 13 2 1 10 1 16 2 2 11 3 4 2 2 14 3 15 2 3 7 3 8 | 0 0 1 12 0 12 A 0 3 A 1 3 3 6 0 6 C 2 8 C 0 8 CB 1 11 CB 0 11 CBA 1 14 CBA 0 14 CBAA 1 14 CBAA 0 11 CBAA 1 11 CBA 0 10 CBA 1 10 CB 1 16 CB 0 16 CBA 0 1 CBA 1 1 CB 0 16 CB 2 16 C 1 8 C 0 8 CA 1 11 CA 0 11 CAA 0 14 CAA 1 14 CA 0 11 CA 1 11 C 0 10 C 3 10 1 0 |
FractalMaze2.in | FractalMaze2.out |
---|---|
8 39 6 1 0 3 17 4 17 5 24 6 2 8 17 5 0 0 1 3 3 6 5 3 5 25 3 0 1 0 8 0 18 4 0 2 0 17 0 22 7 17 4 0 3 0 12 0 31 6 4 4 0 4 0 11 0 27 2 23 5 0 5 0 15 0 19 1 8 3 29 5 0 6 0 9 0 28 1 30 5 6 2 0 7 2 3 2 0 10 2 20 4 0 13 0 16 0 20 8 11 5 0 14 0 21 0 30 0 32 3 23 2 0 23 7 19 2 0 24 7 20 2 0 25 7 10 2 0 26 7 27 2 0 29 8 4 2 1 10 2 2 2 1 14 4 8 2 1 18 2 31 2 1 28 3 9 2 2 12 4 10 2 2 22 4 2 2 3 13 6 1 2 3 20 6 21 2 3 28 5 9 2 4 1 6 9 2 4 18 8 13 2 4 22 6 14 2 4 30 6 11 2 4 32 6 8 2 5 10 6 30 2 5 18 7 5 2 5 21 7 1 2 5 26 5 28 2 6 25 8 7 2 6 32 7 26 2 7 2 8 16 2 7 15 8 27 | 0 0 3 6 0 6 C 1 30 C 0 30 CA 0 14 CA 1 14 C 4 8 C 0 8 CD 0 18 CD 4 18 C 8 13 C 0 13 CH 0 16 CH 8 16 C 7 2 C 0 2 CG 0 17 CG 7 17 C 0 17 C 3 17 1 0 |
第三个实例来源于 http://tieba.baidu.com/p/4335476373(该贴中所绘第一个分形迷宫无解,因为阳极只连在迷宫边缘上,在这种情况下作断路处理)。
如果笔者没有理解错误,那么该分形迷宫的最优解如下:
FractalMaze3.in | FractalMaze3.out |
---|---|
6 35 2 1 0 2 30 2 0 0 6 1 3 0 1 1 3 1 6 2 0 2 0 16 3 0 3 1 9 2 25 3 0 4 2 32 3 29 2 0 5 1 16 2 0 6 2 27 7 0 7 0 8 0 10 0 20 2 20 4 27 5 4 6 0 9 0 12 0 18 3 35 4 19 5 1 6 0 11 0 21 2 18 3 25 4 25 5 16 3 0 13 0 15 1 10 3 0 14 3 32 3 33 3 0 17 0 19 5 14 2 0 22 5 6 2 0 23 5 8 3 0 24 0 26 0 32 3 0 25 0 29 6 5 3 0 27 4 31 6 3 3 0 28 5 11 6 8 2 0 30 5 12 2 0 31 6 12 3 0 33 0 35 5 15 2 0 34 4 29 2 0 36 4 28 2 1 2 2 21 3 1 7 2 34 2 29 2 1 12 3 17 2 2 24 3 19 2 2 36 3 26 2 4 20 4 23 2 4 22 5 2 2 5 10 6 9 2 5 13 6 7 2 6 10 6 15 | 0 0 6 1 0 1 F 1 6 F 0 6 FA 2 27 FA 0 27 FAB 6 3 FAB 0 3 FABF 2 25 FABF 0 25 FABFB 0 29 FABFB 2 29 FABF 1 7 FABF 0 7 FABFA 0 10 FABFA 1 10 FABF 0 15 FABF 6 15 FAB 6 10 FAB 0 10 FABF 0 8 FABF 6 8 FAB 5 11 FAB 0 11 FABE 3 25 FABE 0 25 FABEC 0 29 FABEC 3 29 FABE 0 4 FABE 5 4 FAB 0 20 FAB 2 20 FA 0 10 FA 1 10 F 0 15 F 6 15 6 10 0 10 F 0 8 F 6 8 5 11 0 11 E 3 25 E 0 25 EC 0 29 EC 3 29 E 0 4 E 5 4 2 20 0 20 B 5 4 B 0 4 BE 3 29 BE 0 29 BEC 6 5 BEC 0 5 BECF 1 16 BECF 0 16 BECFA 0 2 BECFA 1 2 BECF 2 21 BECF 0 21 BECFB 4 25 BECFB 0 25 BECFBD 0 29 BECFBD 4 29 BECFB 0 34 BECFB 2 34 BECF 1 7 BECF 0 7 BECFA 0 10 BECFA 1 10 BECF 0 15 BECF 6 15 BEC 6 10 BEC 0 10 BECF 0 7 BECF 6 7 BEC 5 13 BEC 0 13 BECE 0 15 BECE 5 15 BEC 0 35 BEC 3 35 BE 0 12 BE 5 12 B 0 30 B 2 30 1 0 |
结语
分形迷宫结合了迷宫和分形几何学,是值得我们去发掘的。不过可惜的是,从十年前 matrix67 介绍分形迷宫以来,分形迷宫一直未受到重视。对于这样一项如此有前景的技术而言,分形迷宫是不会一直被忽视被冷落的。于是,笔者奉驽马之效,行越俎代庖之事,书此拙文,意欲使分形迷宫扬名于九州。至于水平如何,还请看官斟酌。
公元二〇一六年一十月一十五日