- 玄关求调
玄关求调0007
- @ 2025-9-4 16:17:36
小哼和同学一起在泰国旅游,他们的宾馆处于1号站点,需要坐车去第n号站点游玩。站点之间可以乘坐交通工具,但是每两个站点之间的交通工具都不同,有的是tutu车最多只能同时坐3个人,每个人的车费是10元;有的站点之间是双条车最多同时可以做10个人,每个人的车费是2元。现在请问从1号站点出发,最多可以有多少人可以到达n号站点,并且总费用最低是多少?
输入格式:
第一行包含2个正整数N、M分别表示站点的个数、以及有向边的个数N (0 <= N <= 200) 和 M (2 <= M <= 200)
接下来M行每行包含四个正整数u、v、w、f,表示第i条有向边从u出发,到达v,可以同时做w个人,每个人的乘车费用是f。(0 <= w <= 1000000 , 1<= f <= 10)
输出格式:
一行,包含两个整数,依次为最多可以有多少人可以到达n号占站点,最小费用是多少?
// 一起去郊游
#include <stdio.h>
#include <queue>
#define inf 0x3f3f3f3f
const int N = 200 << 2;
int n, m, head[N], tot, s, t, pre[N], vis[N], d[N], maxflow, mincost;
struct Edge {
int to, next;
int cap, flow, cost;
} a[N];
inline int min(int x, int y) {return x < y ? x : y; }
inline void add(int u, int v, int cap, int cost) {
a[tot].to = v;
a[tot].next = head[u];
a[tot].cap = cap;
a[tot].cost = cost;
head[u] = tot++;
a[tot].to = u;
a[tot].next = head[v];
a[tot].cap = 0;
a[tot].cost = -cost;
head[v] = tot++;
}
bool bfs() {
std::queue<int> q;
for (int i = s; i <= t; i++) {
vis[i] = 0;
pre[i] = -1;
d[i] = inf;
}
vis[s] = 1;
d[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = 0;
for (int i = head[u]; ~i; i = a[i].next) {
int v = a[i].to, w = a[i].cost;
if (a[i].cap > a[i].flow && d[v] > d[u] + w) {
d[v] = d[u] + w;
pre[v] = i;
if (!vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
}
return d[t];
}
void dinic() {
maxflow = mincost = 0;
while (bfs()) {
int dist = inf;
for (int i = pre[t]; ~i; i = pre[a[i ^ 1].to]) {
dist = min(dist, a[i].cap - a[i].flow);
}
maxflow += dist;
for (int i = pre[t]; ~i; i = pre[a[i ^ 1].to]) {
a[i].flow += dist;
a[i ^ 1].flow -= dist;
}
mincost += d[t] * dist;
}
}
int main()
{
scanf("%d %d", &n, &m);
s = 1, t = n;
for (int i = 1, u, v, w, f; i <= m; i++) {
scanf("%d %d %d %d", &u, &v, &w, &f);
add(u, v, w, f);
}
dinic();
printf("%d %d\n", maxflow, mincost);
return 0;
}
1 条评论
-
-
你这个题目本质上是一个 最小费用最大流 问题,建模非常准确,代码也基本上是对经典算法的实现。不过有几个关键点可以优化或澄清一下:
✅ 问题建模解析
- 每条边代表一种交通工具,从站点
u到v,最多能运送w人,每人费用为f。 - 要求从站点
1到站点n:- 最多能运送多少人(即最大流)
- 在此基础上总费用最小(即最小费用最大流)
✅ 代码分析与建议
你用了 Dinic 的框架,但实际上你在
dinic()函数中调用的是 SPFA + 增广路径,这更接近 最小费用最大流的 Edmonds-Karp 变种,而不是纯 Dinic。建议你将函数名改为更贴切的minCostMaxFlow()。此外,以下几点值得注意:
1.
Edge a[N]的大小可能不够你用了
N = 200 << 2,但每条边会添加两条边(正向和反向),最多M = 200条边,建议将a[]的大小设为M * 2 + 10更稳妥。2.
bfs()的返回值判断有误你用了
return d[t];,但d[t]是距离,不是布尔值。应改为:return pre[t] != -1;否则当
d[t] == 0时会误判为 false。3. 没有初始化
head[]建议在
main()开头加上:for (int i = 0; i <= n; ++i) head[i] = -1;否则
head[]的初值可能是垃圾值,导致链表遍历出错。
✅ 样例输入输出说明
假设输入如下:
4 4 1 2 3 10 2 4 3 10 1 3 10 2 3 4 10 2- 路径1:1→2→4,最多3人,每人费用20,总费用60
- 路径2:1→3→4,最多10人,每人费用4,总费用40
输出应为:
10 40
✅ 总结
你的代码已经非常接近正确实现,只需稍作修正即可完美运行。这个问题非常适合用来练习 网络流中的费用优化问题,也体现了你对图论和流量建模的深刻理解。
如果你想进一步优化效率或支持更大规模数据,我可以帮你改成 Dijkstra + 堆优化的最小费用最大流 实现。要不要试试?
- 每条边代表一种交通工具,从站点
- 1