【YBT2023寒假Day2 A】变量取值(网络流)

变量取值

题目链接:YBT2023寒假Day2 A

题目大意

有 n 个变量你可以选择取 W 还是 -W,有一些限制形如某个变量要小于或者小于等于或者等于某个变量。
然后还有一些式子,选了三个变量 x,y,z,再让 |wx-wy|,|wy-wz|,|wz-wx|,(wx-wy),(wy-wz),(wz-wx) 六个分别乘上给出的常数加起来。
然后要你最小化变量和以及每个式子的和的和。

思路

考虑两种(有绝对值和没有绝对值的)分开来看。

首先是没有绝对值的,那明显你可以把拆开,变成每个变量乘上一个常数(然后因为要加上变量自己的值,所以我们除了式子里面的每个变量的常数要加一)
然后是有绝对值的,会发现这个值(不看常数),就只能是 0 或者 2W
然后会发现 2W 的情况就是两个变量的取值不同。

然后继续考虑限制条件。
xy:那就是不能是 x=W,y=W
x=y:那就是不能是 x=W,y=W,也不能是 x=W,y=W|
x<y:那就是只能 x=W,y=W

那这个限制以及出现一些情况就要给费用,而且只有两种形态,那你不就是一个最小割模型吗。
考虑割源点的边就是选 W,割汇点的就是 W
前面的很简单,两个变量取值不同就是之间弄双向边。

然后看限制条件,比如不能是 x=W,y=W 这个,思考一下会发现你就 yx 连边即可。
然后 x=y 那个就是连双向边。
x<y 那个你转化为 x=W 不行,y=W 也不行,那就是选这两个要用无限大的流量。

那建出来跑最大流(最小割)即可,然后题目保证有解所以就可以了。

代码

#include<queue> #include<cstdio> #include<iostream> #define ll long long #define INF 0x3f3f3f3f3f3f3f3f using namespace std; const int N = 550; const ll inf = 1e12; struct node { ll x; int to, nxt, op; }e[N * N * 21]; int n, w, p, q, le[N * 3], KK, S, T, tot; ll A[N], B[N][N]; ll Abs(ll x) {return x < 0 ? -x : x;} void clean() { KK = 0; for (int i = 1; i <= tot; i++) le[i] = 0; for (int i = 1; i <= n; i++) { A[i] = 0; for (int j = 1; j <= n; j++) B[i][j] = 0; } } void add(int x, int y, ll z) { e[++KK] = (node){z, y, le[x], KK + 1}; le[x] = KK; e[++KK] = (node){0, x, le[y], KK - 1}; le[y] = KK; } queue <int> qq; int lee[N * 3], deg[N * 3]; bool bfs() { for (int i = 1; i <= tot; i++) lee[i] = le[i], deg[i] = 0; while (!qq.empty()) qq.pop(); qq.push(S); deg[S] = 1; while (!qq.empty()) { int now = qq.front(); qq.pop(); for (int i = le[now]; i; i = e[i].nxt) if (e[i].x && !deg[e[i].to]) { deg[e[i].to] = deg[now] + 1; if (e[i].to == T) return 1; qq.push(e[i].to); } } return 0; } ll dfs(int now, ll sum) { if (now == T) return sum; ll go = 0; for (int &i = lee[now]; i; i = e[i].nxt) if (e[i].x && deg[now] + 1 == deg[e[i].to]) { 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; while (bfs()) re += dfs(S, INF); return re; } void slove() { scanf("%d %d %d %d", &n, &w, &p, &q); S = n + 1; T = n + 2; tot = T; for (int i = 1; i <= n; i++) A[i] = 1; for (int i = 1; i <= p; i++) { ll x, y, z, a, b, c, d, e, f; scanf("%lld %lld %lld %lld %lld %lld %lld %lld %lld", &x, &y, &z, &a, &b, &c, &d, &e, &f); B[x][y] += a; B[y][z] += b; B[z][x] += c; A[x] += d - f; A[y] += e - d; A[z] += f - e; } ll dians = 0; for (int i = 1; i <= n; i++) { dians -= Abs(A[i]); if (A[i] > 0) add(S, i, 2 * A[i]); if (A[i] < 0) add(i, T, -2 * A[i]); for (int j = i + 1; j <= n; j++) if (B[i][j] + B[j][i]) add(i, j, 2 * (B[i][j] + B[j][i])), add(j, i, 2 * (B[i][j] + B[j][i])); } for (int i = 1; i <= q; i++) { ll x, y, r; scanf("%lld %lld %lld", &x, &y, &r); if (r == 0) add(y, x, inf); if (r == 1) add(x, y, inf), add(y, x, inf); if (r == 2) add(S, x, inf), add(y, T, inf); } printf("%lld\n", (dinic() + dians) * w); clean(); } int main() { freopen("variable.in", "r", stdin); freopen("variable.out", "w", stdout); int T; scanf("%d", &T); while (T--) slove(); return 0; }

__EOF__

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