P2805 [NOI2009] 植物大战僵尸
给定一个 行 列的图,每个点可以保护一些点。
每个点有一个权值(可以为负数)。
如果要选取一个点则必须选取保护它的点以及它右边的点。
试求最大权值和(可以一个点也不选)。
,时限 ,空限 。
sol
容易发现这其实是一道最大权闭合子图的题。
但是需要注意:图可能有环。
也就是说如果你遇到一些植物相互保护的话,是无解的。
所以我们可以用拓扑排序来找出所有的环,在拓扑排序过程中访问到的点才有实际意义。
最后跑一遍最大权闭合子图即可。
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
inline void write(int x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
typedef int tp;
const int _ = 5e5 + 10;
int n, m, s, t, lv[_], cur[_];
int tot = 1, head[_], to[_ << 1], nxt[_ << 1];
tp w[_ << 1];
inline void add(int u, int v, tp dis)
{
to[++tot] = v;
nxt[tot] = head[u];
w[tot] = dis;
head[u] = tot;
}
inline void Add(int u, int v, tp dis)
{
add(u, v, dis);
add(v, u, 0);
}
inline bool bfs()
{
memset(lv, -1, sizeof(lv));
lv[s] = 0;
memcpy(cur, head, sizeof(head));
queue<int> q;
q.push(s);
while (!q.empty())
{
int p = q.front();
q.pop();
for (int eg = head[p]; eg; eg = nxt[eg])
{
int v = to[eg];
tp vol = w[eg];
if (vol > 0 && lv[v] == -1)
lv[v] = lv[p] + 1, q.push(v);
}
}
return lv[t] != -1;
}
tp dfs(int p = s, tp flow = 2e9)
{
if (p == t)
return flow;
tp rmn = flow;
for (int eg = cur[p]; eg && rmn; eg = nxt[eg])
{
cur[p] = eg;
int v = to[eg];
tp vol = w[eg];
if (vol > 0 && lv[v] == lv[p] + 1)
{
tp c = dfs(v, min(vol, rmn));
rmn -= c;
w[eg] -= c;
w[eg ^ 1] += c;
}
}
return flow - rmn;
}
inline tp dinic()
{
tp ans = 0;
while (bfs())
ans += dfs();
return ans;
}
int id(int x, int y)
{
return (x - 1) * m + y;
}
bool vis[_];
int in[_], score[_];
vector<int> out[_];
void toposort()
{
queue<int> Q;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (!in[id(i, j)])
{
Q.push(id(i, j));
vis[id(i, j)] = 1;
}
while (!Q.empty())
{
int u = Q.front();
Q.pop();
for (int i = 0; i < out[u].size(); i++)
{
int v = out[u][i];
in[v]--;
if (!vis[v] && !in[v])
{
Q.push(v);
vis[v] = true;
}
}
}
}
signed main()
{
int x, y, z;
n = read(), m = read();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
score[id(i, j)] = read(), z = read();
for (int k = 1; k <= z; k++)
{
int x = read() + 1, y = read() + 1;
out[id(i, j)].push_back(id(x, y));
in[id(x, y)]++;
}
if (j < m)
{
out[id(i, j + 1)].push_back(id(i, j));
in[id(i, j)]++;
}
}
toposort();
s = 0, t = _ - 1;
int sum = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int u = id(i, j);
if (!vis[u])
continue;
if (score[u] >= 0)
{
Add(s, u, score[u]);
sum += score[u];
}
else
Add(u, t, -score[u]);
for (int k = 0; k < out[u].size(); k++)
{
int v = out[u][k];
if (vis[v])
Add(v, u, 2e9);
}
}
}
write(sum - dinic());
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122028