博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[迷宫中的算法实践]迷宫生成算法——Prim算法
阅读量:5067 次
发布时间:2019-06-12

本文共 5147 字,大约阅读时间需要 17 分钟。

       普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。

——来自百度百科

当我们将Prim算法用于迷宫生成时,情况有些不同,维基百科中给出了随机Prim迷宫生成算法的解释及实现过程:

Randomized Prim's algorithm

This algorithm is a randomized version of .

  1. Start with a grid full of walls.
  2. Pick a cell, mark it as part of the maze. Add the walls of the cell to the wall list.
  3. While there are walls in the list:
    1. Pick a random wall from the list. If the cell on the opposite side isn't in the maze yet:
      1. Make the wall a passage and mark the cell on the opposite side as part of the maze.
      2. Add the neighboring walls of the cell to the wall list.
    2. Remove the wall from the list.

It will usually be relatively easy to find the way to the starting cell, but hard to find the way anywhere else.

Note that simply running classical Prim's on a graph with random edge weights would create mazes stylistically identical to Kruskal's, because they are both minimal spanning tree algorithms. Instead, this algorithm introduces stylistic variation because the edges closer to the starting point have a lower effective weight.

我们将算法实现部分翻译成中文

  1. 让迷宫全都是墙.。
  2. 选一个格,作为迷宫的通路,然后把它的邻墙放入列表.。
  3. 当列表里还有墙时:
    1. 从列表里随机选一个墙,如果它对面的格子不是迷宫的通路:
      1. 把墙打通,让对面的格子成为迷宫的通路.。
      2. 把那个格子的邻墙加入列表。
    2. 如果对面的格子已经是通路了,那就从列表里移除这面墙。

 

       简单研究算法实现过程我们可以发现,Prim算法就是不断地从所有可以是通路的位置中随意选一个挖洞,直到没有可能为通路的位置。

       整个实现过程还是相当于随意为路线附权值的Prim算法。

 

下面我们来做C#下的代码实现:

/// /// 普利姆迷宫生成法/// /// 起始点X坐标/// 起始点Y坐标/// 迷宫宽度/// 迷宫高度/// 迷宫是否含有墙private int[,] Prim(int startX, int startY, int widthLimit, int heightLimit,bool haveBorder){    //block:不可通行    unBlock:可通行    const int block = 0,unBlock = 1;    var r=new Random();    //迷宫尺寸合法化    if (widthLimit < 1)        widthLimit = 1;    if (heightLimit < 1)        heightLimit = 1;    //迷宫起点合法化    if (startX < 0 || startX >= widthLimit)        startX = r.Next(0, widthLimit);    if (startY < 0 || startY >= heightLimit)        startY = r.Next(0, heightLimit);    //减去边框所占的格子    if (!haveBorder)    {        widthLimit--;        heightLimit--;    }    //迷宫尺寸换算成带墙尺寸    widthLimit *= 2;    heightLimit *= 2;    //迷宫起点换算成带墙起点    startX *= 2;    startY *= 2;    if (haveBorder)    {        startX++;        startY++;    }    //产生空白迷宫    var mazeMap = new int[widthLimit + 1, heightLimit + 1];    for (int x = 0; x <= widthLimit; x++)    {        //mazeMap.Add(new BitArray(heightLimit + 1));        for (int y = 0; y <= heightLimit; y++)        {            mazeMap[x, y] = block;        }    }    //邻墙列表    var blockPos = new List
(); //将起点作为目标格 int targetX = startX, targetY = startY; //将起点标记为通路 mazeMap[targetX, targetY] = unBlock; //记录邻墙 if (targetY > 1) { blockPos.AddRange(new int[] { targetX, targetY - 1, 0 }); } if (targetX < widthLimit) { blockPos.AddRange(new int[] { targetX + 1, targetY, 1 }); } if (targetY < heightLimit) { blockPos.AddRange(new int[] { targetX, targetY + 1, 2 }); } if (targetX > 1) { blockPos.AddRange(new int[] { targetX - 1, targetY, 3 }); } while (blockPos.Count > 0) { //随机选一堵墙 var blockIndex = r.Next(0, blockPos.Count / 3) * 3; //找到墙对面的墙 if (blockPos[blockIndex + 2] == 0) { targetX = blockPos[blockIndex]; targetY = blockPos[blockIndex + 1] - 1; } else if (blockPos[blockIndex + 2] == 1) { targetX = blockPos[blockIndex] + 1; targetY = blockPos[blockIndex + 1]; } else if (blockPos[blockIndex + 2] == 2) { targetX = blockPos[blockIndex]; targetY = blockPos[blockIndex + 1] + 1; } else if (blockPos[blockIndex + 2] == 3) { targetX = blockPos[blockIndex] - 1; targetY = blockPos[blockIndex + 1]; } //如果目标格未连通 if (mazeMap[targetX, targetY] == block) { //联通目标格 mazeMap[blockPos[blockIndex], blockPos[blockIndex + 1]] = unBlock; mazeMap[targetX, targetY] = unBlock; //添加目标格相邻格 if (targetY > 1 && mazeMap[targetX, targetY - 1] == block && mazeMap[targetX, targetY - 2] == block) { blockPos.AddRange(new int[] { targetX, targetY - 1, 0 }); } if (targetX < widthLimit && mazeMap[targetX + 1, targetY] == block && mazeMap[targetX + 2, targetY] == block) { blockPos.AddRange(new int[] { targetX + 1, targetY, 1 }); } if (targetY < heightLimit && mazeMap[targetX, targetY + 1] == block && mazeMap[targetX, targetY + 2] == block) { blockPos.AddRange(new int[] { targetX, targetY + 1, 2 }); } if (targetX > 1 && mazeMap[targetX - 1, targetY] == block && mazeMap[targetX - 1, targetY] == block) { blockPos.AddRange(new int[] { targetX - 1, targetY, 3 }); } } blockPos.RemoveRange(blockIndex, 3); } return mazeMap;}

转载于:https://www.cnblogs.com/WayneShao/p/5890379.html

你可能感兴趣的文章
第2周学习进度
查看>>
修改系统的shell
查看>>
Opencv DNN 物体检测
查看>>
C++定义动态数组
查看>>
步步为营-84-数字转化为金额的Js+enter键取消页面刷新
查看>>
插入排序
查看>>
反刍我的傻瓜时代(四)
查看>>
try...catch...
查看>>
IE6中 PNG 背景透明的最佳解决方案
查看>>
easyui设置行的背景色
查看>>
JavaScript学习总结【8】、面向对象编程
查看>>
【HackerRank】Gem Stones
查看>>
Octopress技巧之设置关键字和描述
查看>>
ajax学习
查看>>
数据库的优化
查看>>
【转】tar打包解压详解
查看>>
【hadoop】【demo】HBase shell
查看>>
GTK: about Building GTK+ 3.0
查看>>
MySQL 5.7的安装及主从复制(主从同步)
查看>>
互联网公司站点通病之弱口令
查看>>