BZOJ 1565 [NOI2009]植物大战僵尸 | 网络流
2018-01-19 15:15
369 查看
传送门
题解
这道题也是个经典的最大权闭合子图……
复习一下最大权闭合子图是什么?
就是一个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 , _nxt[M], _go[M], _ecnt; #define id(x, y) (x * m + y + 1) int ecnt = 1, adj , cur , dis , nxt[M], go[M], cap[M]; int low , dfn , idx, stk , top; bool ins , mark ; 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 , 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; }
相关文章推荐
- 【XSY1996】【BZOJ1565】【NOI2009】植物大战僵尸 网络流 最大权闭合子图
- [BZOJ1565][NOI2009]植物大战僵尸-拓扑排序-网络流
- [bzoj1565][NOI2009]植物大战僵尸_网络流_拓扑排序
- Bzoj1565 [NOI2009]植物大战僵尸
- bzoj 1565: [NOI2009]植物大战僵尸
- [BZOJ]1565: [NOI2009]植物大战僵尸 Tarjan+最小割(最大权闭合子图)
- bzoj1565 [NOI2009]植物大战僵尸
- bzoj1565: [NOI2009]植物大战僵尸 最小割
- bzoj 1565 [NOI2009]植物大战僵尸 解题报告
- 【bzoj1565】【NOI2009】【植物大战僵尸】【拓扑排序+最小割】
- bzoj 1565: [NOI2009]植物大战僵尸 最大权闭合子图+拓扑排序
- 1565: [NOI2009]植物大战僵尸 - BZOJ
- bzoj 1565 [NOI2009]植物大战僵尸 解题报告
- 【BZOJ 1565】[NOI2009]植物大战僵尸
- bzoj 1565 [NOI2009]植物大战僵尸【tarjan+最大权闭合子图】
- BZOJ1565: [NOI2009]植物大战僵尸 最小割 拓扑排序
- BZOJ 1565 [NOI2009]植物大战僵尸
- 【bzoj1565】[NOI2009]植物大战僵尸 最大权闭合图+拓扑排序
- BZOJ 1565: [NOI2009]植物大战僵尸
- BZOJ1565: [NOI2009]植物大战僵尸