P4012 深海机器人问题 题解

简单费用流。

考虑每个点 (x,y)(x,y) 转化成 (x1)×(p+1)+y+16(x-1) \times (p+1) + y+16。加上 1616 是为了避免结果为负数或 00

题目限制只能往上或往右,于是对于每个点 uu,找到上边和右边的点。由于上边和右边本质类似,以上边为例,设其为 vv

由于每条边只会被在第一次走过时计算贡献,所以连 ucap=1,cost=wvu \xrightarrow{cap=1,cost=w} vww 是这条边的贡献。然而尽管第一次走算贡献,但接着这条路仍然可以走,只不过没有贡献,所以还要连 ucap=+,cost=0vu \xrightarrow{cap=+\infty,cost=0} v

对于每个起点 uu,连 Scap=k,cost=0uS \xrightarrow{cap=k,cost=0} u。对于每个终点 vv,连 vcap=k,cost=0Tv \xrightarrow{cap=k,cost=0} T。跑最大费用最大流即可。

#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;
}
posted @ 2023-07-13 19:03  HappyBobb  阅读(10)  评论(0)    收藏  举报  来源