[洛谷]P2648 赚钱(点权转化为边权+spfa+超级源点)
发布人:shili8
发布时间:2024-12-28 07:00
阅读次数:0
**赚钱**
**题目描述**
在一个由 $n$ 个城市组成的图中,每个城市都有一个权值。每次行走到相邻城市的成本为1。现在,给定了 $m$ 条边,每条边都有一个权值和一个点权。如果我们从某个城市出发,经过一系列的城市,然后回到起始城市,我们可以获得相应的总点数。
**任务**
求出从每个城市出发,经过一系列的城市,然后回到起始城市所能获得的最大总点数。
**思路**
这个问题可以使用 Dijkstra 算法来解决。我们首先将所有城市的权值都加上1,这样就变成了一个标准的最短路径问题。然后,我们使用 Dijkstra 算法找到从每个城市出发到达其他城市所需的最短距离。
**超级源点**
在这个算法中,我们需要找到一个超级源点,即一个城市,它可以到达所有其他城市。我们可以通过检查每个城市是否能到达所有其他城市来实现这一点。如果某个城市不能到达所有其他城市,那么它就不是超级源点。
**代码示例**
cpp#include <iostream> #include <vector> #include <queue> using namespace std; const int N =100010; typedef long long ll; struct Edge { int to, next; }; int n, m, s, t; ll dis[N]; Edge e[N << 1]; void add(int u, int v) { e[m].to = v; e[m].next = head[u]; head[u] = m++; } int head[N], tot; void init() { for (int i =0; i <= n; i++) { dis[i] =1e18; head[i] = -1; } tot =0; } bool spfa() { queue<int> q; for (int i =0; i <= n; i++) if (dis[i] ==1e18) dis[i] =0, q.push(i); while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if (dis[v] > dis[u] +1) { dis[v] = dis[u] +1; if (!q.empty() && q.front() == v) q.pop(); q.push(v); } } } return dis[t] !=1e18; } ll dfs(int u, ll flow) { if (u == t || !flow) return flow; ll res =0; for (int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if (dis[v] == dis[u] +1 && e[i].next != -1) { ll tmp = dfs(v, min(flow, e[i].next)); res += tmp; flow -= tmp; e[i].next -= tmp; e[i ^1].next += tmp; if (!flow) return res; } } return res; } ll dinic() { ll res =0; while (spfa()) res += dfs(s,1e18); return res; }
**超级源点的实现**
cppbool is_super_source(int u) { for (int i = head[u]; ~i; i = e[i].next) if (!vis[e[i].to]) return false; return true; } void find_super_source() { vis.assign(n +1, false); super_source = -1; for (int i =0; i <= n; i++) if (is_super_source(i)) super_source = i; }
**使用超级源点的实现**
cppll dinic_with_super_source() { ll res =0; while (spfa()) { for (int i = head[super_source]; ~i; i = e[i].next) if (!vis[e[i].to]) vis[e[i].to] = true, res += dfs(e[i].to,1e18); vis.assign(n +1, false); } return res; }
**使用超级源点的实现**
cppint main() { init(); // ... find_super_source(); ll ans = dinic_with_super_source(); cout << ans << endl; return0; }
以上是对这个问题的解决方案。