当前位置:实例文章 » 其他实例» [文章][洛谷]P2648 赚钱(点权转化为边权+spfa+超级源点)

[洛谷]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;
}


以上是对这个问题的解决方案。

相关标签:
其他信息

其他资源

Top