一直都只会费用流的暴力增广,但这次被卡住了:在一个二分图上暴力增广,增广的次数至少也是 O(n) 级别的,也就是说需要做 O(n) 次 SPFA 。这样写还不如写搜索划算。
多路增广怎么做呢?其实其过程很像 dinic :每次求出一个最短路网,然后对于其上的节点用 dfs 增广。每次增广完的路径上的节点要求将其标记清零:因为其有可能再次出现在最短路网中。接着像 dinic 一样:找到增广路上最早的一个有流量的点,继续重复以上过程增广即可。
虽然这道题还是只有 80 分(二分图最佳匹配,满分算法好像是 KM)。但是相对于暴力增广的 40 分来说:暴力增广一次只能增广不到一百的费用,而多路增广一次可以增广最大费用 39303 的费用(其十分之九),说明效率提升还是很大的。
Code :
#include
#include
#include
#include
#define maxn 451
#define maxs 905
#define maxm 400005
#define ppp(e) (ve + (e - ve ^ 1))
int n, m, cnt, S, T, Q, co, h, t, tt;
int x[maxm], y[maxm], xx[maxm], yy[maxm], ans[maxm], dis[maxs], q[maxs], pre[maxs], vst[maxs];
int a[maxn][maxn];
bool b[maxn][maxn];
char ss[10];
struct da{int t, w, f; da * n;} ve[maxm], * adj = ve + 1, * edge[maxs], * prev[maxs];
inline void link(int i, int j, int k)
{
* (++ adj) = (da) {j, k, 1, edge[i]}, edge[i] = adj;
* (++ adj) = (da) {i, - k, 0, edge[j]}, edge[j] = adj;
}
bool spfa()
{
memset(dis, 0xEE, T + 1 << 2), dis[S] = q[S] = 0, ++ tt;
for (h = t = S; h; vst[h] = 0, h = q[h])
for (da * e = edge[h]; e; e = e->n)
if (e->f && dis[h] + e->w > dis[e->t])
if (dis[e->t] = dis[h] + e->w, vst[e->t] != tt)
vst[e->t] = tt, q[e->t] = 0, t = q[t] = e->t;
return dis[T] >= 0;
}
inline void extend()
{
co += dis[T];
for (int i = T; prev[i]; i = pre[i])
prev[i]->f = 0, ppp(prev[i])->f = 1;
}
bool dfs(int u)
{
if (u == T) {extend(); return 1;}
else vst[u] = tt;
for (da * e = edge[u]; e; e = e->n)
if (vst[e->t] != tt && e->f && dis[u] + e->w == dis[e->t])
{
pre[e->t] = u, prev[e->t] = e;
if (dfs(e->t) && u != S) {vst[u] = 0; return 1;}
}
return 0;
}
int main()
{
freopen("c.in", "r", stdin);
freopen("b.out", "w", stdout);
scanf("%d%d%d", & n, & m, & cnt);
S = n + m + 1, T = S + 1;
for (int i = 1; i <= cnt; ++ i)
scanf("%d%d", x + i, y + i), scanf("%d", & a[x[i]][y[i]]);
scanf("%d", & Q);
for (int i = 1; i <= Q; ++ i)
if (scanf("%s", ss), * ss == 'A') xx[i] = yy[i] = - 1;
else scanf("%d%d", xx + i, yy + i), b[xx[i]][yy[i]] = 1;
for (int i = 1; i <= n; ++ i) link(S, i, 0);
for (int i = 1; i <= m; ++ i) link(n + i, T, 0);
for (int i = 1; i <= cnt; ++ i)
if (! b[x[i]][y[i]]) link(x[i], n + y[i], a[x[i]][y[i]]);
for (int i = Q; i; -- i)
if (~ xx[i]) link(xx[i], n + yy[i], a[xx[i]][yy[i]]);
else
{
co = 0;
for (da * e = ve + 2; e <= adj; ++ e) e->f = 1, (++ e)->f = 0;
while (spfa()) ++ tt, dfs(S);
ans[i] = co;
}
for (int i = 1; i <= Q; ++ i)
if (xx[i] == - 1) printf("%d\n", ans[i]);
return 0;
}