Luogu P4311 【士兵占领】
Description
Solution
首先如果士兵只能给一行或一列造成贡献的答案是\(\sum_{i = 1}^m l_i + \sum_{i = 1}^n c_i\)。
但是发现有的士兵可以同时给一列和一行造成贡献。
那就算出这些士兵的个数就行了。
\(S\)向每一行连容量为\(l_i\)的有向边;每一列向\(T\)连容量为\(c_i\)的有向边。
如果坐标\((i,j)\)不是障碍,那么第\(i\)行向第\(j\)列连容量为\(1\)的有向边。
跑出来的最大流就是贡献为\(2\)的士兵数量。
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int INF = 999999999;
const int N = 10050;
const int M = 200050;
int n, m, s, t, head[N], num = 1, dis[N], k, l[150], c[150], p[150][150], sum[500], ans;
struct Node
{
int next, to, dis;
} edge[M * 2];
void Addedge(int u, int v, int w)
{
edge[++num]= (Node){head[u], v, w};
head[u] = num;
}
template <class T>
void Read(T &x)
{
x = 0; int p = 0; char st = getchar();
while (st < '0' || st > '9') p = (st == '-'), st = getchar();
while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
x = p ? -x : x;
return;
}
template <class T>
void Put(T x)
{
if (x < 0) putchar('-'), x = -x;
if (x > 9) Put(x / 10);
putchar(x % 10 + '0');
return;
}
bool Bfs()
{
queue<int> q;
for (int i = 0; i <= t; i++) dis[i] = 0;
dis[s] = 1; q.push(s);
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i = head[u]; i; i = edge[i].next)
if (!dis[edge[i].to] && edge[i].dis)
{
dis[edge[i].to] = dis[u] + 1;
q.push(edge[i].to);
if (edge[i].to == t) return 1;
}
}
return 0;
}
int Dinic(int x, int flow)
{
if (x == t || !flow) return flow;
int rest = flow;
for (int i = head[x]; i && rest; i = edge[i].next)
if (edge[i].dis && dis[edge[i].to] == dis[x] + 1)
{
int v = edge[i].to;
int tmp = Dinic(v, min(flow, edge[i].dis));
rest -= tmp;
edge[i].dis -= tmp;
edge[i ^ 1].dis += tmp;
if (!tmp) dis[v] = 0;
}
return flow - rest;
}
void Add(int u, int v, int w)
{
Addedge(u, v, w);
Addedge(v, u, 0);
return;
}
int Maxflow()
{
int maxflow = 0, tmp;
while (Bfs())
{
tmp = Dinic(s, INF);
if (tmp) maxflow += tmp;
}
return maxflow;
}
int main()
{
Read(m); Read(n); Read(k);
for (int i = 1; i <= m; i++) Read(l[i]), ans += l[i];
for (int i = 1; i <= n; i++) Read(c[i]), ans += c[i];
int x, y;
for (int i = 1; i <= k; i++) Read(x), Read(y), p[x][y] = 1;
s = 0, t = n + m + 1;
for (int i = 1; i <= m; i++) Add(s, i, l[i]);
for (int i = 1; i <= n; i++) Add(i + m, t, c[i]);
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
{
if (!p[i][j])
Add(i, j + m, 1);
sum[i] = sum[i] + !p[i][j];
sum[j + m] = sum[j + m] + !p[i][j];
}
for (int i = 1; i <= m; i++) if (sum[i] < l[i]) { puts("JIONG!"); return 0; }
for (int j = 1; j <= n; j++) if (sum[j + m] < c[j]) { puts("JIONG!"); return 0; }
Put(ans - Maxflow());
return 0;
}