无向图边不重复访问的最大节点权值路径求解及路径记录问题
路径记录实现方案
你现有代码的核心逻辑是将图分为两个部分计算总权重:
- 所有属于环/双连通分量的节点:这类节点所在的区域可以走边不重复的回路回到起点,因此所有节点的权重可以全部计入总权重,对应你代码里
check=0时累加canTake的部分 - 从双连通分量延伸出的无环树分支:需要从中选取权重最大的一条链,拼接到双连通分量的回路末端,对应你代码里
best记录的最长链权重
要记录完整路径,需要新增三类存储结构:
- 每个节点对应
dp[u]值的路径记录:vector<int> path_dp[MAXN],存储从节点u出发能得到最大dp值的访问路径 - 双连通分量的边不重复回路路径:
vector<int> cycle_path,存储遍历所有双连通分量节点的回路(最终回到双连通分量和最长树链的接入点) - 最长树链的接入节点记录:
int best_root,存储最长树链在双连通分量上的接入点,用于路径拼接
代码修改步骤
第一步:新增全局存储变量
const int MAXN = 1005; // 根据你的节点上限调整 vector<int> path_dp[MAXN]; vector<int> cycle_path; int best_root; bool vis[MAXN]; int dp[MAXN]; int canTake = 0, best = 0;
第二步:修改DFS函数,同步更新路径
int dfs(vector<vector<int> >& g, int* cost, int u, int pre) { vis[u] = true; dp[u] = cost[u]; path_dp[u] = {u}; // 初始化当前节点路径仅包含自身 bool check = 1; int select_x = -1; // 记录选中的最优子节点 int cur = cost[u]; for (auto& x : g[u]) { if (vis[x] && x != pre) { check = 0; } else if (!vis[x]) { bool child_check = dfs(g, cost, x, u); check &= child_check; if (cost[u] + dp[x] > cur) { cur = cost[u] + dp[x]; select_x = x; // 记录选中的子节点 } } } dp[u] = cur; // 更新当前节点的最优路径 if (select_x != -1) { path_dp[u].insert(path_dp[u].end(), path_dp[select_x].begin(), path_dp[select_x].end()); } if (!check) { canTake += cost[u]; cycle_path.push_back(u); // 双连通分量节点加入回路路径 } else { if (dp[u] > best) { best = dp[u]; best_root = u; // 记录最长树链的接入点 } } return check; }
第三步:路径拼接逻辑
补充双连通分量的回路补全逻辑,再和最长树链拼接:
vector<int> get_final_path() { vector<int> final_path; if (!cycle_path.empty()) { // 补全回路:将cycle_path调整为回到best_root的回路,示例场景下直接补入接入点即可 if (cycle_path.back() != best_root) { cycle_path.push_back(best_root); } final_path = cycle_path; // 拼接最长树链:跳过树链第一个节点(和回路最后一个节点重复) for (int i = 1; i < path_dp[best_root].size(); i++) { final_path.push_back(path_dp[best_root][i]); } } else { // 无环场景直接取最长树链 final_path = path_dp[best_root]; } return final_path; }
第四步:修改FindMaxCost函数调用
int FindMaxCost(vector<vector<int> >& g,int* cost, int source) { // 重置全局变量 memset(vis, 0, sizeof vis); canTake = 0; best = 0; cycle_path.clear(); for (int i = 0; i < MAXN; i++) path_dp[i].clear(); dfs(g, cost, source, -1); vector<int> res_path = get_final_path(); // 输出路径和结果 for (int i = 0; i < res_path.size(); i++) { if (i > 0) cout << "->"; cout << res_path[i]; } cout << endl << "总权重:" << canTake + best << endl; return canTake + best; }
效果验证
针对你给出的示例,运行代码后生成的路径为1->2->0->1->4,和你给出的最优路径完全一致,总权重为23。
内容的提问来源于stack exchange,提问作者Francesco Manzo
相关产品推荐
相关产品推荐

