BZOJ 1565 [NOI2009]植物大战僵尸 | 网络流
传送门
题解
这道题也是个经典的最大权闭合子图……
复习一下最大权闭合子图是什么?
就是一个DAG上,每个点有个或正或负的点权,有的点依赖于另外一些点(如果选这个点,则被依赖点必选),问选出一些点的权值和最大是多少。
这个问题怎么解决?
网络流建图,被依赖点向依赖点连INF的边,若某点权为正则源点向它连相应容量的边,否则它向汇点连点权的绝对值容量的边。
问题是……这道题是有环的……
有环也没关系,按照题意,环上的点都不能选,那么直接让环上的所有点向汇点连INF边即可。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long ll;
#define enter putchar('\n')
#define space putchar(' ')
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c > '9' || c < '0')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 605, M = 1000005, INF = 0x3f3f3f3f;
int n, m, src, des, ans;
int _adj[N], _nxt[M], _go[M], _ecnt;
#define id(x, y) (x * m + y + 1)
int ecnt = 1, adj[N], cur[N], dis[N], nxt[M], go[M], cap[M];
int low[N], dfn[N], idx, stk[N], top;
bool ins[N], mark[N];
void ADD(int u, int v, int w){
go[++ecnt] = v;
nxt[ecnt] = adj[u];
adj[u] = ecnt;
cap[ecnt] = w;
}
void add(int u, int v, int w){
ADD(u, v, w);
ADD(v, u, 0);
}
void _add(int u, int v){
_go[++_ecnt] = v;
_nxt[_ecnt] = _adj[u];
_adj[u] = _ecnt;
}
bool bfs(){
static int que[N], qr;
for(int i = 1; i <= des; i++)
cur[i] = adj[i], dis[i] = -1;
dis[src] = 0, que[qr = 1] = src;
for(int ql = 1; ql <= qr; ql++)
for(int u = que[ql], e = adj[u], v; e; e = nxt[e])
if(cap[e] && dis[v = go[e]] == -1)
dis[v] = dis[u] + 1, que[++qr] = v;
return dis[des] != -1;
}
int dfs(int u, int flow){
if(u == des) return flow;
int ret = 0;
for(int &e = cur[u], v; e; e = nxt[e])
if(cap[e] && dis[v = go[e]] == dis[u] + 1){
int delta = dfs(v, min(cap[e], flow - ret));
if(delta){
cap[e] -= delta;
cap[e ^ 1] += delta;
ret += delta;
if(ret == flow) return ret;
}
}
dis[u] = -1;
return ret;
}
int maxflow(){
int ret = 0;
while(bfs()) ret += dfs(src, INF);
return ret;
}
void tarjan(int u){
stk[++top] = u, ins[u] = 1;
low[u] = dfn[u] = ++idx;
for(int e = _adj[u], v; e; e = _nxt[e])
if(v = _go[e], !dfn[v])
tarjan(v), low[u] = min(low[u], low[v]);
else if(ins[v])
low[u] = min(low[u], dfn[v]);
if(low[u] == dfn[u]){
int v = stk[top];
if(v == u) top--, ins[u] = 0;
else
while(v != u){
ins[v = stk[top--]] = 0;
mark[v] = 1;
}
}
}
int main(){
read(n), read(m), src = n * m + 1, des = n * m + 2;
for(int i = 0, k, w, x, y, num = 1; i < n; i++)
for(int j = 0; j < m; j++, num++){
if(j) _add(num - 1, num), add(num - 1, num, INF);
read(w), read(k);
if(w >= 0) add(src, num, w), ans += w;
else add(num, des, -w);
while(k--){
read(x), read(y);
_add(id(x, y), num);
add(id(x, y), num, INF);
}
}
for(int i = 1; i <= n * m; i++)
if(!dfn[i]) tarjan(i);
for(int i = 1; i <= n * m; i++)
if(mark[i]) add(i, des, INF);
write(ans - maxflow()), enter;
return 0;
}
本文作者:胡小兔
博客地址:http://rabbithu.cnblogs.com
博客地址:http://rabbithu.cnblogs.com