概要:
dfsブルートフォース検索。図の任意の固定点iを開始点として検索を開始し、dfsを介して各パスを検索し、重みが最大のパスを見つけます。
トピックの簡単な説明(問題の変換):
有向加重グラフであるnポイントは、隣接行列を示します。最大の重みを持つパスを見つける
LuoguP1966
アルゴリズムの分析:
点数nが非常に少ないので、したがって、dfsブルートフォース検索方法を使用できます。
問題の分析は、各ポイントで特定の数の地雷を掘ることができ、この条件を前のポイントと次のポイントの間のエッジの重みに変換できることを示しています。
この質問は、単純なグラフ理論の詳細な検索とは異なります。その中の各ポイントは何度でもトラバースできるため、単に訪問配列を使用して、トラバースされたすべてのポイントにアクセスできないものとしてマークを付けることはできません。代わりに、最初にマークを付けてからバックトラックしてブロックを解除する方法を使用して
ください。詳細については、次のコードを参照してください。
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;
}