本来在学习dfs相关算法,在书上看到了一个水管连通的例子,恰好最近又玩过星穹铁道,我记得里面有一个小任务就是帮助NPC连接电路,和算法书上涉及到的算法很相似,感觉挺有意思的,就把书上的算法小改了一下。
这里我们以书上的类型为例(简单一些QAQ),总共有6种线路类型,和4个连接的朝向(上下左右)。要选择合适的线路型号,从而找出一条连接起点和终点的通路。
话不多说,以上图的起点和终点位置为例,上代码:
#include <iostream>
using namespace std;
int a[51][51];//假设线路大小不超过50*50
int book[51][51];//标记线路是否使用过
int n, m, flag = 0;//flag用来判断是否找到了一条线路
struct node
{
//横纵坐标
int x;
int y;
//线路型号
int style;
}s[100];
int top = 0;
//使用DFS算法
void dfs(int x, int y, int front, int style)//参数解释:x, y是当前线路的位置坐标,front是前一条线路接入的方向,style前一条线路的型号
{
//此处特别声明,因为每次线路连接好后,要传入此线路连接的下一个点的坐标
//所以当连接到终点时,需要判断的是连接终点的下一个点的坐标
//此例子中终点的位置在(n,m)并且线路终点在右边,所以要判断y与m + 1的关系
//此处判断根据终点的具体位置变化
if(x == n && y == m + 1)
{
//找到了线路
flag = 1;
//记录线路型号
s[top].style = style;
//输出结果
for(int i = 1; i <= top; i++)
{
cout << "(" << s[i].x << "," << s[i].y << ")"<< " style: " << s[i].style << endl;
}
return ;
}
//判断是否越界
if(x < 0 || x > n || y < 0 || y > m )
{
return ;
}
//判断此线路是否在路径中已经使用过
if(book[x][y] == 1)
{
return ;
}
//标记当前线路
book[x][y] = 1;
//将当前的线路信息入栈(包括坐标和线路类型)
top++;
s[top].x = x;
s[top].y = y;
//style是前一条线路的型号,所以这里要top - 1来使线路坐标与线路型号相匹配
s[top - 1].style = style;
//当线路为直线的情况
if(a[x][y] >= 5 && a[x][y] <= 6)
{
if(front == 1)//从左边接入线路
{
dfs(x, y + 1, 1, 5);//只能采取5号类型的线路
}
if(front == 2)//从上方接入线路
{
dfs(x + 1, y, 2, 6);//只能采取6号类型的线路
}
if(front == 3)//从右边接入线路
{
dfs(x, y - 1, 3, 5);//只能采取5号类型的线路
}
if(front == 4)//从下方接入线路
{
dfs(x - 1, y, 4, 6);//只能采取6号类型的线路
}
}
//当线路为弯曲的情况
if(a[x][y] >= 1 && a[x][y] <= 4)
{
if(front == 1)
{
dfs(x + 1, y, 2, 3);//3号线路
dfs(x - 1, y, 4, 4);//4号线路
}
if(front == 2)
{
dfs(x, y + 1, 1, 1);//1号线路
dfs(x, y - 1, 3, 4);//4号线路
}
if(front == 3)
{
dfs(x - 1, y, 4, 1);//1号线路
dfs(x + 1, y, 2, 2);//2号线路
}
if(front == 4)
{
dfs(x, y + 1, 1, 2);//2号线路
dfs(x, y - 1, 3, 3);//3号线路
}
}
//取消标记,将当前尝试坐标出栈
book[x][y] = 0;
top--;
return ;
}
int main()
{
//输入线路板大小
//初始化线路板
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
for(int j = 1 ; j <= m; j++)
{
cin >> a[i][j];
}
}
//从(1,1)开始,线路从左边接入,由于是线路起点,所以没有线路型号
dfs(1, 1, 1, 0);
//判断是否找到可行线路
if(flag == 0)
{
cout << "Fail" << endl;
}
return 0;
}
代码中的注释应该比较详细了,所以我也不过多赘述。星穹铁道中的电路有6个朝向,而例子中只有4个朝向,算是一个简化版吧。