C++版图类型搜索方法

案例1:走迷宫

一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走;有的格子是空地可以走。给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到)。只能在水平和垂直走,不能斜着走。

输入:R和C代表迷宫的长和宽(1<=R,C<=40)

空地用.表示,障碍物用#表示。迷宫左上角和右下角都为.。

输出:从左上角走到右下角至少要经过多少步(即至少要经过多少个空地格子)。

输入:

5 5

..###

#....

#.#.#

#.#.#

#.#..

输出:9


求解思路:

map[R][C]:.#构成的障碍物图

vis[R][C]:0-1矩阵变量,用于记录地图上的位置是否已经遍历过

arc[4][2]={{0,-1},{-1,0},{0,1},{1,0}}:左上右下情况下横轴和纵轴量的变化情况

用dfs(int row, int col, int step)来进行相应的深度优先遍历,设置深度优先遍历的回溯条件是超出边界(row<0||row>R||col<0||col>C)或者是 已经遍历过vis[row][col]=1 或者是遇到障碍物map[row][col]='#'。

设置深度优先遍历结果比较出口,到达了右下角(row=R && col=C)。


C++代码:

#include<iostream>

#include<limits>

using namespace std;

char map[50][50];

int mina = std::numeric_limits<int>::max();

int R, C;

bool vis[50][50];

int arc[4][2] = { {0,1},{-1,0},{0,1},{1,0} };

void dfs(int row, int col, int step) {

if (row == R && col == C) {

if (mina > step) {

mina = step;

return;

}

}

else {

for (int i = 0; i < 4; i++) {

int x = row + arc[i][0];

int y = col + arc[i][1];

if (x < 0 || x > R || y < 0 || y > C || map[x][y] == '#' || vis[x][y])

continue;

vis[x][y] = 1;

dfs(x, y, step + 1);

vis[x][y] = 0;

}

}

}

int main() {

cin >> R >> C;

R--;

C--;

for (int i = 0; i <= R; i++) {

for (int j = 0; j <= C; j++)

cin >> map[i][j];

}

dfs(0, 0, 1);

cout << mina << endl;

return 0;

}


案例2:走迷宫

有一个nm格的迷宫(表示有n行m列),其中有可走的也有不可走的。如果用1表示可走的,0表示不可走,文件读入这nm个数据点和起始点、终点(起始点和终点都是用两个数据描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可走的道路,要求所有的路中没有重复的点,走时只能上下左右四个去向。如果一条路不可行,则输出相应的信息(用-1表示无路)

输入:第一行是2个数n,m(1<n,m<15),接下来n行m列由1和0组成的数据。最后2行是起始点和结束点

如:

5 6

1 0 0 1 0 1

1 1 1 1 1 1

0 0 1 1 1 0

1 1 1 1 1 0

1 1 1 0 1 1

1 1

5 6

输出:

(1,1)->(2,1)->(2,2)->...->(5,6)

(1,1)->(2,1)->(2,2)->...->(5,6)

...


求解思路:

此案例相较于案例有两个额外的需求:(1)输出完整的路径序列结果;(2)输出的完整路径序列结果不能有重复的路径点;

int ans[105][2]:用于记录算法中每一步迭代路径点的x和y值;

bool opt[R][C]:   用于判断算法输出的结果的路径点是否重复;


C++代码:

#include<iostream>

#include<stdio.h>

#include<string.h>

using namespace std;

int map[20][20];

int route[105][2];

int arc[4][2] = { {0,-1}, {-1,0}, {0,1}, {1,0} };

bool opt[20][20];

bool vis[20][20];

int n, m;

int startn, startm;

int endn, endm;

bool is_suc = false;

void dfs(int row, int col, int step) {

if (row == endn && col == endm) {

memset(opt, 0, sizeof(opt));

for (int i = 1; i <= step; i++) {

if (opt[route[i][0]][route[i][1]] == 1) return;

else opt[route[i][0]][route[i][1]] = 1;

}

cout << "(" << route[1][0] << "," << route[1][1] << ")";

for (int i = 2; i <= step; i++) {

cout << "->(" << route[i][0] << "," << route[i][1] << ")";

}

cout << endl;

is_suc = true;

}

else {

for (int i = 0; i < 4; i++) {

int x = row + arc[i][0];

int y = col + arc[i][1];

if (x <= 0 || x > n || y <= 0 || y > m)

continue;

if (map[x][y] == 0 || vis[x][y])

continue;

vis[x][y] = 1;

route[step + 1][0] = x;

route[step + 1][1] = y;

dfs(x, y, step+1);

vis[x][y] = 0;

}

}

}

int main() {

cin >> n >> m;

for (int i = 1; i <= n; i++) {

for (int j = 1; j <= m; j++)

cin >> map[i][j];

}

cin >> startn >> startm;

cin >> endn >> endm;

route[1][0] = startn;

route[1][1] = startm;

dfs(startn, startm, 1);

if (!is_suc)

cout << "-1" << endl;

return 0;

}


案例3:最小开门数

小明家有很大的房子,有很多房间。先输入roomA,然后输入roomB,再输入门的个数N(N<=100)。接着输入N行门,意味着从一个房间(第一个数字,int型)到另一个房间(第二个数字)。请问roomA到roomB最短要经过几个门。

输入:

1

5

5

1 2

2 3

3 4

2 5

4 5

输出: 2


求解思路1:暴力回溯搜索法(会超时)

int A[101]、B[101]:记录这N对门之间的房间号

bool vis[max_Int]: 记录第i个房间是否已经访问

bool arr[max_Int][max_Int]:记录房间之间是否有连接关系

#include<iostream>

#include<cstring>

#include<limits>

#define max_Int 2000

using namespace std;

int ans, roomA, roomB, N;

int A[101], B[101];

bool vis[max_Int]; //记录第i个房间是否已经访问

bool arr[max_Int][max_Int]; //记录房间之间是否有连接关系

void dfs(int cur, int step) { //从cur房间号开始搜索

if (cur == roomB) {

if (step < ans) {

ans = step;

}

return;

}

else {

for (int i = 0; i < N; i++) {

if ((vis[B[i]] == 0) && (arr[cur][B[i]] == 1 || arr[B[i]][cur] == 1)) {

//B[i]没走过,有B[i]到cur的门

vis[B[i]] = 1; //尝试走

dfs(B[i], step + 1);

vis[B[i]] = 0;

}

if ((vis[A[i]] == 0) && (arr[A[i]][cur] == 1 || arr[cur][A[i]] == 1)) {

//A[i]没走过,有A[i]到cur的门

vis[A[i]] = 1;

dfs(A[i], step + 1);

vis[A[i]] = 0;

}

}

}

}

int main() {

while (cin >> roomA >> roomB >> N) {

ans = max_Int;

memset(vis, 0, sizeof(vis));

memset(A, 0, sizeof(A));

memset(B, 0, sizeof(B));

memset(arr, 0, sizeof(arr));

for (int i = 0; i < N; i++) {

cin >> A[i] >> B[i];

arr[A[i]][B[i]] = 1;

arr[B[i]][A[i]] = 1;

}

vis[roomA] = 0;

dfs(roomA, 0);

cout << ans << endl;

}

return 0;

}

求解思路2:广度优先搜索法(successful)

bool arc[205][205]:邻接矩阵,用于存放图中顶点之间的是否可达

bool vis[205]:存放顶点是否已经访问

vector<int>vertex:存放顶点实际编号信息

int que[205]:广度游戏遍历的队列信息

#include<iostream>

#include<vector>

#include<cstring>

#include<algorithm>

#include<stdio.h>

using namespace std;

int froom, eroom, N, roomA, roomB;

int front, rear;

bool arc[205][205]; //邻接矩阵,用于存放图中顶点之间的联系

bool vis[205];      //存放顶点是否已经访问信息

vector<int> vertex; //存放顶点实际编号信息

int que[205];      //广度优先遍历的队列信息

int bfsearch(int fr) {

//从顶点fr进行广度优先遍历

int ans = 0;

int sz = vertex.size();

int v = -1;

int step[205]; //记录走到的步数

memset(step, 0, sizeof(step));

for (int i = 0; i < sz; i++) {

if (vertex[i] == fr) {

v = i;

break;

}

}

if (v == -1)

return -1; //不可走

front = rear = -1;

vis[v] = 1;

que[++rear] = v;

while (front <= rear) {

int i;

v = que[++front]; //出队

for (i = 0; i < sz; i++) {

if (arc[v][i] == 1 && !vis[i]) {

que[++rear] = i;

vis[i] = 1;

step[rear] = step[front] + 1; //单层找到长度+1

if (vertex[i] == eroom) {

return step[rear];

}

}

}

}

}

int main() {

while (cin >> froom >> eroom >> N) {

memset(arc, 0, sizeof(arc));

memset(vis, 0, sizeof(vis));

memset(que, 0, sizeof(que));

vertex.clear();

int ra, rb, shortestDis;

for (int i = 0; i < N; i++) {

cin >> roomA >> roomB;

int sz = vertex.size();

for (ra = 0; ra < sz; ra++) {

if (vertex[ra] == roomA)

break;

}

if (ra == sz) { //roomA不在顶点列表中

vertex.push_back(roomA);

}

sz = vertex.size();

for (rb = 0; rb < sz; rb++) {

if (vertex[rb] == roomB)

break;

}

if (rb == sz) { //roomB不在顶点列表中

vertex.push_back(roomB);

}

arc[ra][rb] = 1;

arc[rb][ra] = 1;

}

shortestDis = bfsearch(froom);

if (shortestDis == -1) {

cout << "找不到" << endl;

}

else {

cout << shortestDis << endl;

}

}

return 0;

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容