2021-02-26 洛谷P1966挖地雷——dfs暴力搜索(回溯法)

摘要:

dfs暴力搜索。以图中任意一个定点i为起点开始搜索,通过dfs搜索每一条路径,找出权重最大的一条。


题目简述(问题转化):

n个点,有向加权图,给出邻接矩阵。求一条最大权重的路径
洛谷P1966


算法分析:

由于点数n很小,因此可以采用dfs暴力搜索的方法。
分析题目可知,每到一个点,都可以挖到一定数量的地雷,可将这个条件转化为上一个点到下一个点之间的边的权重大小。
这道题和简单的图论中的深度搜索不一样。这里面的每一个点可以遍历任意多次,因此不可以简单的用一个visit数组,将之前遍历过的点全部标记为不可访问。而应该采用先标记后回溯解封的方法
详见如下代码:

dfs()
	...
	for j in 某点i的邻接点数组//a[i]表示点i的邻接点
		if(visit[i]==true) //证明已经访问过
			continue;
		visit[a[i][j]]=true;  //先标记为已到达过
		path[step+1]=a[i][j]; 
		dfs(a[i][j],当前步数+1,当前的权重+这一步的权重w[a[i][j]])
		visit[a[i][j]]=false; //回溯解封

代码以及详细注释:

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
#pragma warning(disable:4996)


class Solution {
public:
	int  n, m;
	vector<int> w;
	vector<int> path;
	vector<bool>visit;
	vector<vector<int>> a;
	int ans = 0;
	int count = 0;
	vector<int> res;
	void func() {
		cin >> n;
		w.resize(n + 1);
		for (int i = 1; i <= n; ++i)
			cin >> w[i];
		a.resize(n+1);
		visit.resize(n + 1, false);
		path.resize(n + 1);
		for(int i=1;i<n;++i)
			for (int j = i + 1; j <= n; ++j)
			{
				int x;
				cin >> x;
				if(x==1)
					a[i].push_back(j);
			}

		for (int i = 1; i <= n; ++i)
		{
			path[1] = i;
			visit[i] = true;
			dfs(i, 1, w[i]);
			visit[i] = false;
		}
		for (int i = 1; i <= count; ++i)
			cout << res[i] << " ";
		cout << endl << ans;
	}

	void dfs(int i,int step,int cur) 
	{
		if (a[i].empty())
		{
			if (ans < cur )
			{
				ans = cur;
				res = path;
				count = step;
			}
			return;
		}
		for (int j = 0; j<int(a[i].size()); ++j)
		{
			if (visit[a[i][j]])continue;
			visit[a[i][j]] = true;
			path[step + 1] = a[i][j];
			dfs(a[i][j], step + 1, cur + w[a[i][j]]);
			visit[a[i][j]] = false;
		}
	}
};
	
int main() {
	//freopen("in.txt", "r", stdin);
	Solution s;
	s.func();
	return 0;
}

上一篇:图的遍历实现


下一篇:友元成员函数