zoukankan      html  css  js  c++  java
  • DFS

    思想

    从起点出发,标记走过的点,如果发现没有走过的点,随便选一个向前走,无路可走就回退。
    在这里插入图片描述

    应用

    • 判断从V出发能否走到终点
      在这里插入图片描述
      - 判断从V出发能否走到终点,若能,记录路径
    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的二进制形式0001001001001000,所以只要将输入数字与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
    %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
    ", 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
    ", minLen);
    	}
    	else
    		printf("-1
    ");
    
    	return 0;
    }
    

    4、生日蛋糕
    在这里插入图片描述在这里插入图片描述
    练习1
    练习2
    练习3

    参考郭炜老师MOOC

  • 相关阅读:
    小白自动化测试指南
    分布式性能测试框架用例方案设想(二)
    高QPS下的固定QPS模型
    测试自动化最佳实践【译】
    moco框架接口命中率统计实践
    基于docker的分布式性能测试框架功能验证(一)
    编写高质量代码:Web前端开发修炼之道(一)
    JavaScript中点操作符和中括号操作符区别
    Vue脚手架生成及配置
    Npm设置淘宝镜像
  • 原文地址:https://www.cnblogs.com/EIMadrigal/p/12130895.html
Copyright © 2011-2022 走看看