1 条题解
-
0
自动搬运
来自洛谷,原作者为

Rusalka
愿旅途上充满了无尽的诅咒与祝福搬运于
2025-08-24 22:17:20,当前版本为作者最后更新于2020-07-27 23:51:32,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
原题链接:P6094 [JSOI2015]圈地
题意简述
-
把一块 的地分给两个人,选择分出第 行第 列的地可以获得 的收益。
-
要在两个人分到的地中间建墙,使得两个人分到的地完全隔离,建两个格子之间的墙需要花费一定代价。
-
最大化总收益与总代价的差
-
-
细节还是见原题吧QAQ
思路与解答
-
你看它数据范围这么小肯定是个图论建模,而且大概率网络流 -
你看这题相当于要把地分成两块,并且代价最小。
-
那就是一个最小割嘛
-
然后考虑怎么建图
-
你在建图时需要保证能选或不选一块地,并且要能够“割”开两块属于不同的人的地
-
假设两个人分别为 A 和 B,那么首先把相邻两块地之间连边,流量为建墙的花费,表示如果要“割”开这两块地就要砍掉这条边,当然要不要砍再说;注意这里无法保证你要怎么“割”,所以两块地要分别向对方连边。
-
那么之后建一个超级源点 ,把 和所有 A 想要的地连边,流量为这块地的收益,如果在权衡之后不选,就把这条边“割”掉;同理,把所有 B 想要的地和超级汇点 连边,流量也为这块地的收益。
-
那么你在这张图中跑一遍最小割,得到的结果就是你需要付出的最小代价,这里是包括了选或者不选一块地。
-
所以你只需要把总收益,即所有结点的收益和减去最小割即可。
-
最后,你只需要知道最小割等于最大流,就可以愉快的切题了
Code
#include <cstdio> #include <queue> #include <iostream> #include <cstring> #define abs(x) (x<0?-x:x) using namespace std; const int MAXN = 80010; const int INF = 0x3f3f3f3f; int n, m; inline int id(int i, int j){return (i-1)*m+j;} struct edge{ int ne, to, fl; edge(int N=0,int T=0,int F=0):ne(N),to(T),fl(F){} }e[MAXN*6]; int fir[MAXN], num = 1; int s, t; inline void adde(int a, int b, int c) { e[++num] = edge(fir[a], b, c); fir[a] = num; } inline void join(int a, int b, int c) { adde(a, b, c); adde(b, a, 0); } int dep[MAXN], cur[MAXN]; queue<int> q; bool bfs(int s, int t) { for(int i=0;i<=n*m+1;i++) dep[i] = 0, cur[i] = fir[i]; while(!q.empty()) q.pop(); q.push(s); dep[s] = 1; while(!q.empty()) { int u = q.front(); q.pop(); for(int i=fir[u];i;i=e[i].ne) { int v = e[i].to; if(dep[v] || !e[i].fl) continue; dep[v] = dep[u] + 1; q.push(v); } } return dep[t]; } int dfs(int u, int fln) { if(u == t) return fln; int res = 0; for(int& i=cur[u];i;i=e[i].ne) { int v = e[i].to; if(!e[i].fl || dep[v] != dep[u]+1) continue; int sum = dfs(v, min(fln, e[i].fl)); e[i].fl -= sum; e[i^1].fl += sum; fln -= sum; res += sum; if(!fln) break; } if(!res) dep[u] = 0; return res; } inline int dinic() { int res = 0; while(bfs(s, t)) res += dfs(s, INF); return res; } int main() { scanf("%d%d",&n,&m); s = 0; t = n*m+1; int sum = 0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { int a; scanf("%d",&a); if(a > 0) join(s, id(i, j), a); if(a < 0) join(id(i, j), t, -a); sum += abs(a); } } for(int i=1;i<n;i++) { for(int j=1;j<=m;j++) { int a; scanf("%d",&a); join(id(i, j), id(i+1, j), a); join(id(i+1, j), id(i, j), a); } } for(int i=1;i<=n;i++) { for(int j=1;j<m;j++) { int a; scanf("%d",&a); join(id(i, j), id(i, j+1), a); join(id(i, j+1), id(i, j), a); } } printf("%d\n",sum-dinic()); return 0; } -
- 1
信息
- ID
- 5122
- 时间
- 2000ms
- 内存
- 500MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者