摘要:
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;
}