题解:P9902 『PG2』模拟最大流
比较好的 DP 题。第一反应是暴力跑最大流,但是卡常难度极高,所以就算了 QAQ。
注意到这是一个 DAG,有拓扑序
直接从最大流 DP 似乎不太可行,使用经典 Trick 最大流转最小割,直接设
因为你让
接着是
不妨设
很好理解,就是加上最后一条边的贡献。初始有
其中箭头表示 chkmin。统计答案的时候,只需要要求
#include <bits/stdc++.h>
#define rep(i, l, r) for(int i = (l); i <= (r); i ++ )
#define per(i, l, r) for(int i = (l); i >= (r); i -- )
#define ctz(x) __builtin_ctz(x)
#define endl '\n'
using namespace std;
const int N = 8e4 + 5;
const int K = 8, INF = 0x3f3f3f3f;
int n, m, k, e[N][K], dp[N][1 << K], f[N][1 << K];
inline int& chkmin(int &x, int v) { return x = x < v ? x : v;}
int main() {
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> k;
rep(i, 1, m) {
int u, v, w;
cin >> u >> v >> w;
if(u == v) continue;
e[v][v - u] += w;
}
memset(dp, 0x3f, sizeof dp);
rep(S, 0, (1 << (k - 1)) - 1) dp[1][S << 1 | 1] = 0;
rep(i, 1, n) {
rep(S, 1, (1 << k) - 1)
f[i][S] = f[i][S ^ (1 << ctz(S))] + e[i + 1][ctz(S) + 1];
}
rep(i, 1, n) {
rep(S, 0, (1 << k) - 1) {
chkmin(dp[i + 1][(S << 1 | 1) & ((1 << k) - 1)], dp[i][S]);
chkmin(dp[i + 1][(S << 1) & ((1 << k) - 1)], dp[i][S] + f[i][S]);
}
}
int ans = INF;
rep(S, 0, (1 << (k - 1)) - 1) chkmin(ans, dp[n][S << 1]);
cout << ans << endl;
return 0;
}