P4012 深海机器人问题 题解
简单费用流。
考虑每个点 转化成 。加上 是为了避免结果为负数或 。
题目限制只能往上或往右,于是对于每个点 ,找到上边和右边的点。由于上边和右边本质类似,以上边为例,设其为 。
由于每条边只会被在第一次走过时计算贡献,所以连 , 是这条边的贡献。然而尽管第一次走算贡献,但接着这条路仍然可以走,只不过没有贡献,所以还要连 。
对于每个起点 ,连 。对于每个终点 ,连 。跑最大费用最大流即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int p, q, n, m, S, T;
int e[N], h[N], c[N], cs[N], ne[N], idx;
int dis[N], cur[N], res = 0;
bool isin[N];
inline void add(int u, int v, int w, int cc)
{
cc = -cc;
e[idx] = v, c[idx] = w, cs[idx] = cc, ne[idx] = h[u], h[u] = idx++;
e[idx] = u, c[idx] = 0, cs[idx] = -cc, ne[idx] = h[v], h[v] = idx++;
}
inline int get(int x, int y)
{
return (x - 1) * (p + 1) + y + 16;
}
inline bool spfa()
{
for (int i = 0; i <= T; i++) dis[i] = 2e9, cur[i] = -1;
dis[S] = 0, cur[S] = h[S];
queue<int> q;
q.push(S);
while (q.size())
{
int u = q.front();
q.pop();
isin[u] = 0;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (dis[j] > dis[u] + cs[i] && c[i] > 0)
{
dis[j] = dis[u] + cs[i];
cur[j] = h[j];
if (!isin[j])
{
q.push(j);
isin[j] = 1;
}
}
}
}
return (dis[T] != 2e9);
}
inline int dfs(int u, int lim)
{
if (u == T) return lim;
isin[u] = 1;
int sum = 0;
for (int i = cur[u]; ~i && sum < lim; i = ne[i])
{
cur[u] = i;
int j = e[i];
if (!isin[j] && dis[j] == dis[u] + cs[i] && c[i] > 0)
{
int p = dfs(j, min(c[i], lim - sum));
sum += p;
c[i] -= p;
c[i ^ 1] += p;
res += p * cs[i];
}
}
isin[u] = 0;
return sum;
}
inline void dinic()
{
while (spfa())
{
while (dfs(S, INT_MAX));
}
}
int main()
{
memset(h, -1, sizeof h);
S = 5000, T = 5001;
scanf("%d%d", &n, &m);
scanf("%d%d", &p, &q);
for (int i = 0; i <= p; i++)
{
int nowx = 0;
for (int j = 1; j <= q; j++)
{
int ds;
scanf("%d", &ds);
add(get(nowx, i), get(nowx + 1, i), 1, ds);
add(get(nowx, i), get(nowx + 1, i), INT_MAX, 0);
nowx++;
}
}
for (int i = 0; i <= q; i++)
{
int nowy = 0;
for (int j = 1; j <= p; j++)
{
int ds;
scanf("%d", &ds);
add(get(i, nowy), get(i, nowy + 1), 1, ds);
add(get(i, nowy), get(i, nowy + 1), INT_MAX, 0);
nowy++;
}
}
for (int i = 1; i <= n; i++)
{
int k, x, y;
scanf("%d%d%d", &k, &x, &y);
add(S, get(y, x), k, 0);
}
for (int i = 1; i <= m; i++)
{
int k, x, y;
scanf("%d%d%d", &k, &x, &y);
add(get(y, x), T, k, 0);
}
dinic();
printf("%d\n", -res);
return 0;
}

浙公网安备 33010602011771号