【luogu AGC031E】Snuke the Phantom Thief(网络流)

Snuke the Phantom Thief

题目链接:luogu AGC031E

题目大意

有 n 个特殊点分布在二维平面上,每个点有坐标和价值。
你要选一些点,总价值是你选的点的价值和。
然后有一些约束,横坐标或者纵坐标大于等于或者小于等于某个值的你选了的点的数量不能超过某个数。
要你最大化总价值。

思路

看到范围会感觉可以用费用流做。
不过按着题目的感觉弄,会发现一个问题,就是你可以算出每个方向上的最严限制,然后每个要选的点就要满足多个条件。
但你是很难做到的,因为你不能让一条边要么不流,要么流满。

所以考虑换一下思路,尝试将题目的条件转化再建模。
发现把条件反过来一下,也就是一个限制变成你选的前 k 个点或者后 k 个点的横坐标或纵坐标要小于等于或大于等于某个数。
那换句话说,我们尝试从一个区间的点的限制规划到一个点的,就是第 k+1 个点的横坐标或者纵坐标要大于或者小于某个数。

不过要注意的一点是横纵坐标应该是分开的,因为我们这里的第 k 个点在横纵坐标里面可能并不是同一个点,是按横坐标或者纵坐标排序得到的第 k 个点。
那我们就有建图的想法了,首先我们枚举一个 k 表示我们选多少个点。

然后源点 S 连到左边的 k 个点,右边的 k 个点连到汇点 T,表示选点。
然后你考虑所有的 n 个点,进行一个拆点,之间的边的费用就是点权。
然后你考虑左边的 k 个点表示按横坐标排序,右边的 k 个点表示按纵坐标排序。
那你一个点 x 可以跟左边或者后边的某个点 y 连接就是要它处在这个位置的时候可以满足我们的限制。
(这个限制我们可以预处理出来,就是按前面的确立关系,然后前缀和后缀和一下)

然后跑费用流就行。
不过要注意的是它这里是要费用最大,所以把费用改成小 infv,然后费用流加的时候就是流量乘(小 infdisT

代码

#include<queue> #include<cstdio> #include<iostream> #define ll long long #define INF 0x3f3f3f3f3f3f3f3f using namespace std; const ll N = 85; const ll M = 350; const ll inf = 1e15; struct Dian { ll x, y, op, z; }a[N], b[M]; struct node { ll x, cst, to, nxt, op; }e[N * M * 2 * 2]; ll n, m, S, T, le[(N + M) * 2], KK; ll L[N], R[N], U[N], D[N], ans; void add(ll x, ll y, ll z, ll cst) { e[++KK] = (node){z, cst, y, le[x], KK + 1}; le[x] = KK; e[++KK] = (node){0, -cst, x, le[y], KK - 1}; le[y] = KK; } ll deg[(N + M) * 2], lee[(N + M) * 2]; ll dis[(N + M) * 2]; bool in[(N + M) * 2]; queue <ll> q; bool SPFA() { for (ll i = 1; i <= T; i++) deg[i] = in[i] = 0, dis[i] = INF, lee[i] = le[i]; while (!q.empty()) q.pop(); ll chk = dis[T]; q.push(S); dis[S] = 0; deg[S] = 1; in[S] = 1; while (!q.empty()) { ll now = q.front(); q.pop(); for (ll i = le[now]; i; i = e[i].nxt) if (dis[e[i].to] > dis[now] + e[i].cst && e[i].x) { dis[e[i].to] = dis[now] + e[i].cst; deg[e[i].to] = deg[now] + 1; if (!in[e[i].to]) { in[e[i].to] = 1; q.push(e[i].to); } } in[now] = 0; } return dis[T] != chk; } ll dfs(ll now, ll sum) { if (now == T) return sum; ll go = 0; for (ll &i = lee[now]; i; i = e[i].nxt) if (e[i].x & dis[e[i].to] == dis[now] + e[i].cst && deg[e[i].to] == deg[now] + 1) { ll this_go = dfs(e[i].to, min(sum - go, e[i].x)); if (this_go) { e[i].x -= this_go; e[e[i].op].x += this_go; go += this_go; if (go == sum) return go; } } deg[now] = -1; return go; } ll Dinic() { ll re = 0, cnt = 0; while (SPFA()) { ll x = dfs(S, INF); re += x * (inf - dis[T]); } return re; } ll work(ll k) { S = (n + k) * 2 + 1, T = S + 1; for (ll i = 1; i <= k; i++) { add(S, i, 1, 0); add(i + k, T, 1, 0); } for (ll i = 1; i <= n; i++) { for (ll j = 1; j <= k; j++) { if (L[j] <= a[i].x && a[i].x <= R[k - j + 1]) add(j, 2 * k + i, 1, 0); if (D[j] <= a[i].y && a[i].y <= U[k - j + 1]) add(2 * k + n + i, j + k, 1, 0); } add(2 * k + i, 2 * k + n + i, 1, inf - a[i].z); } ll re = Dinic(); for (ll i = 1; i <= T; i++) le[i] = 0; KK = 0; return re; } int main() { scanf("%lld", &n); for (ll i = 1; i <= n; i++) { scanf("%lld %lld %lld", &a[i].x, &a[i].y, &a[i].z); } scanf("%lld", &m); for (ll i = 0; i <= n + 1; i++) R[i] = U[i] = inf; for (ll i = 1; i <= m; i++) { char c = getchar(); while (c != 'L' && c != 'R' && c != 'U' && c != 'D') c = getchar(); if (c == 'L') b[i].op = 0; if (c == 'R') b[i].op = 1; if (c == 'D') b[i].op = 2; if (c == 'U') b[i].op = 3; scanf("%lld %lld", &b[i].x, &b[i].y); if (b[i].op == 0) L[b[i].y + 1] = max(L[b[i].y + 1], b[i].x + 1); if (b[i].op == 1) R[b[i].y + 1] = min(R[b[i].y + 1], b[i].x - 1); if (b[i].op == 2) D[b[i].y + 1] = max(D[b[i].y + 1], b[i].x + 1); if (b[i].op == 3) U[b[i].y + 1] = min(U[b[i].y + 1], b[i].x - 1); } for (ll i = 1; i <= n; i++) L[i] = max(L[i], L[i - 1]), R[i] = min(R[i], R[i - 1]), D[i] = max(D[i], D[i - 1]), U[i] = min(U[i], U[i - 1]); //预处理关系 for (ll i = 1; i <= n; i++) ans = max(ans, work(i)); printf("%lld", ans); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_AGC031E.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示