标签:mat using cto learn 描述 数组 ota org 地图
从起点出发,标记走过的点,如果发现没有走过的点,随便选一个向前走,无路可走就回退。


Node path[MAX_LEN];     //MAX_LEN取节点总数即可
int depth;   //当前点的深度
bool Dfs(V)
{
    if (V为终点)
    {
        path[depth] = V;
        return true;
    }
    if (V为旧点)
    {
        return false;
    }
    将V标记为旧点;
    path[depth++] = V;
    对和V相邻的每个节点U
    {
        if (Dfs(U))
            return true;
    }
    --depth;   //从V走不到终点,把V排除出数组,回退到V的父节点
    return false;
}
int main()
{
    所有点标记为新点;
    depth = 0;
    if (Dfs(起点))
    {
        for (int i = 0; i <= depth; i++)
        {
            cout << path[i] << endl;
        }
    }
    return 0;
}- 遍历图上所有节点

邻接矩阵存储遍历复杂度\(O(n^2)\),因为对每个节点,都要判断其它所有节点是否相邻。
邻接表遍历复杂度\(O(n+e)\)。
1、城堡问题
给一个地图以及每个格子周围的墙所代表数字之和,求该地图有多少房间,最大房间的面积。
分析:
要先判断每个格子周围有什么墙,注意到1,2,4,8的二进制形式0001、0010、0100、1000,所以只要将输入数字与1,2,4,8相与,就能知道该方块周围有什么墙。
把方块看作节点,相邻两个方块如果没有墙,就在这两节点之间连一条边,转换为图。
房间个数:图中的极大连通子图个数
极大连通子图:一个连通子图,加任意一个图中的其他点就不连通,这个子图就是极大连通子图。
具体:
对每个房间进行DFS,得到该房间所在的极大连通子图,染色所有能够到达的房间,最后统计共用了几种颜色以及每种颜色的数量。
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int room[50][50];
int color[50][50] = { 0 };   //标记方块是否染色,初始都未被访问
int maxRoomArea = 0, roomNum = 0, curRoomArea = 0;
void Dfs(int i,int j)   //从i,j出发遍历极大连通子图
{
    if (color[i][j])
        return;
    color[i][j] = roomNum;   //该方块染色
    curRoomArea++;
    if ((room[i][j] & 1) == 0) Dfs(i, j - 1);  //没有西墙,向西走
    if ((room[i][j] & 2) == 0) Dfs(i - 1, j);
    if ((room[i][j] & 4) == 0) Dfs(i, j + 1);
    if ((room[i][j] & 8) == 0) Dfs(i + 1, j);
}
int main()
{
    int row, column;
    scanf("%d%d", &row, &column);
    for (int i = 0; i < row; i++)
        for (int j = 0; j < column; j++)
        {
            scanf("%d", &room[i][j]);
        }
    for (int i = 0; i < row; i++)
        for (int j = 0; j < column; j++)
        {
            if (!color[i][j])   //找到一个新的房间
            {
                roomNum++;
                curRoomArea = 0;
                Dfs(i, j);          //探索该房间(极大连通子图)
            }
            maxRoomArea = max(curRoomArea, maxRoomArea);
        }
    printf("%d\n%d", roomNum, maxRoomArea);
    return 0;
}2、踩方格
递归,从\((i,j)\)出发走n步的方案数就等于先走一步,从其它三个格子走n-1步的方案数之和。
前提就是该方块没走过。
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
bool isVisited[20][20] = { 0 };
int Dfs(int i, int j, int n)
{
    int ans = 0;
    //访问过直接返回
    if (isVisited[i][j])
        return 0;
    //递归边界
    if (0 == n)
        return 1;
    isVisited[i][j] = true;
    //可以走三个方向
    ans += Dfs(i - 1, j, n - 1);
    ans += Dfs(i, j - 1, n - 1);
    ans += Dfs(i, j + 1, n - 1);
    //返回前表示当前格子可以重新被访问,以后的走法可能会访问到
    isVisited[i][j] = false;
    return ans;
}
int main()
{
    int n;
    scanf("%d", &n);
    printf("%d\n", Dfs(20, 20, n));
    return 0;
}3、ROADS
很多时候,并不需要一条路走到黑,这就是深搜中的剪枝。

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <sstream>
#include <string>
using namespace std;
/*存储边,不需要起点,G(i)表示从i出发*/
struct Road {
    int destination, len, toll;
};
/*邻接表存储图*/
vector<vector<Road>> G(110);
int k, n, r;
int minLen;   //探索过的最短的路径
int totalLen;   //正在探索的最短路径
int totalCost;   //正在探索的花费
int visited[110];
int minL[110][10010]; //minL[i][j]:从1走到城市i,且花了j块钱的最优路径长度
void dfs(int s)
{
    if (s == n)   //找到了路径
    {
        minLen = min(minLen, totalLen);
        return;   //强制结束函数
    }
    int len = G[s].size();
    for (int i = 0; i < len; i++)
    {
        Road r = G[s][i];
        /*判断有没有足够的钱走到r.destination*/
        if (totalCost + r.toll > k) //钱不够,试下一条边
            continue;     //可行性剪枝
        if (!visited[r.destination])
        {
            /*最优性剪枝*/
            //当前走过的路长度已经大于之前的minLen,就没必要走下去
            if (totalLen + r.len >= minLen)
                continue;
            //走到r.d时花费同样的钱走过的路长度大于之前相同花费的路长度
            if (totalLen + r.len >= minL[r.destination][totalCost + r.toll])
                continue;
            minL[r.destination][totalCost + r.toll] = totalLen + r.len;
            totalLen += r.len;
            totalCost += r.toll;
            visited[r.destination] = 1;
            dfs(r.destination);
            /*不走r.destination*/
            visited[r.destination] = 0; //换下条边之前将访问标志清0
            totalLen -= r.len;
            totalCost -= r.toll;
        }
    }
}
/*从城市1开始深搜整个图,找到所有能到达n的,选最优的*/
int main()
{
    scanf("%d%d%d", &k, &n, &r);
    
    for (int i = 0; i < r; i++)
    {
        int source;
        Road r;
        scanf("%d%d%d%d", &source, &r.destination, &r.len, &r.toll);
        if (source != r.destination)
        {
            G[source].push_back(r);
        }
    }
    memset(visited, 0, sizeof(visited));
    totalLen = 0, totalLen = 0;
    minLen = 1 << 30;   //置为无穷大
    for (int i = 0; i < 110; i++)
        for (int j = 0; j < 10010; j++)
            minL[i][j] = 1 << 30;
    visited[1] = 1;
    dfs(1);  //走完了所有路
    if (minLen < (1 << 30))
    {
        printf("%d\n", minLen);
    }
    else
        printf("-1\n");
    return 0;
}参考郭炜老师MOOC
标签:mat using cto learn 描述 数组 ota org 地图
原文地址:https://www.cnblogs.com/EIMadrigal/p/12130895.html