BZOJ1565 [NOI2009]植物大战僵尸 【最大权闭合子图 + tarjan缩点(或拓扑)】
2018-01-03 14:26
281 查看
题目
输入格式
输出格式
仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。输入样例
3 210 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0
输出样例
25提示
在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。
【大致数据规模】
约20%的数据满足1 ≤ N, M ≤ 5;
约40%的数据满足1 ≤ N, M ≤ 10;
约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。
题解
僵尸想吃一个植物,首先得吃掉它前面的植物和保护它的植物这就是有附属关系的最大权选择问题,即最大权闭合子图
但是要注意图中的环是无敌的,我们要忽略掉这些点
可以用tarjan或拓扑找环
还没完
被环保护的点也是无敌的,所以还要从环出发排除掉被环保护的点【一开始没注意到这个WA了2发】
#include<iostream> #include<cmath> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define REP(i,n) for (int i = 1; i <= (n); i++) #define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt) using namespace std; const int maxn = 1005,maxm = 2000005,INF = 1000000000; inline int RD(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();} return out * flag; } int s[maxn],id[22][32],N,M,cnt = 0,S,T,f[maxn]; int h[maxn],ne = 0; struct EDGE{int to,nxt,f;}ed[maxm]; void build(int u,int v,int f){ ed[ne] = (EDGE){v,h[u],f}; h[u] = ne++; ed[ne] = (EDGE){u,h[v],0}; h[v] = ne++; } int dfn[maxn],low[maxn],Scc[maxn],scci = 0,Siz[maxn],st[maxn],top = 0,Cnt = 0; void dfs(int u){ low[u] = dfn[u] = ++Cnt; st[++top] = u; int to; Redge(u){ if (k & 1) continue; if (!dfn[to = ed[k].to]) dfs(to); if (!Scc[to]) low[u] = min(low[u],low[to]); } if (dfn[u] == low[u]){ scci++; do {Scc[st[top]] = scci; Siz[scci]++;}while (st[top--] != u); } } void tarjan(){ REP(i,cnt) if (!dfn[i]) dfs(i); } int d[maxn],vis[maxn],cur[maxn]; bool bfs(){ queue<int> q; int u,to; for (int i = S; i <= T; i++) d[i] = INF,vis[i] = false; q.push(S); vis[S] = true; d[S] = 0; while (!q.empty()){ u = q.front(); q.pop(); Redge(u) if (ed[k].f && !f[to = ed[k].to] && !vis[to]){ d[to] = d[u] + 1; vis[to] = true; q.push(to); } } return vis[T]; } int dfs(int u,int minf){ if (u == T || !minf) return minf; int flow = 0,f,to; if (cur[u] == -2) cur[u] = h[u]; for (int& k = cur[u]; k != -1; k = ed[k].nxt) if (d[to = ed[k].to] == d[u] + 1 && (f = dfs(to,min(ed[k].f,minf)))){ ed[k].f -= f; ed[k ^ 1].f += f; flow += f; minf -= f; if (!minf) break; } return flow; } int maxflow(){ int flow = 0; while (bfs()){ fill(cur,cur + maxn,-2); flow += dfs(S,INF); } return flow; } void dfs1(int u){ f[u] = true; Redge(u) if ((k & 1) && !f[ed[k].to]) dfs1(ed[k].to); } int main(){ memset(h,-1,sizeof(h)); N = RD(); M = RD(); int t,x,y,tot = 0; REP(i,N) REP(j,M) id[i - 1][j - 1] = ++cnt; for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) if (j + 1 < M) build(id[i][j],id[i][j + 1],INF); S = 0; T = cnt + 1; for (int i = 1; i <= cnt; i++){ s[i] = RD(); t = RD(); while (t--) x = RD(),y = RD(),build(id[x][y],i,INF); } tarjan(); REP(i,cnt) if (Siz[Scc[i]] > 1) dfs1(i); REP(i,cnt) if (!f[i]){ if (s[i] >= 0) build(S,i,s[i]),tot += s[i]; else build(i,T,-s[i]); } printf("%d",tot - maxflow()); return 0; }
相关文章推荐
- BZOJ1565 [NOI2009]植物大战僵尸 【最大权闭合子图 + tarjan缩点(或拓扑)】
- bzoj1565 [NOI2009]植物大战僵尸(拓扑序+最大权闭合子图,最小割)
- BZOJ1565 [NOI2009]植物大战僵尸(拓扑排序 + 最大权闭合子图)
- [BZOJ]1565: [NOI2009]植物大战僵尸 Tarjan+最小割(最大权闭合子图)
- Bzoj 1565: [NOI2009]植物大战僵尸 最大权闭合图,拓扑排序
- bzoj 1565 [NOI2009]植物大战僵尸【tarjan+最大权闭合子图】
- bzoj 1565: [NOI2009]植物大战僵尸 (最大权闭合子图+tarjan+拓扑序)
- bzoj 1565: [NOI2009]植物大战僵尸 最大权闭合子图+拓扑排序
- 【XSY1996】【BZOJ1565】【NOI2009】植物大战僵尸 网络流 最大权闭合子图
- [BZOJ1565][NOI2009]植物大战僵尸(tarjan+最小割)
- BZOJ_1565_[NOI2009]_植物大战僵尸_(Tarjan+最大流+最大权闭合图)
- [BZOJ 1565][NOI 2009]植物大战僵尸(Dinic最大流+拓扑排序)
- 【bzoj1565】[NOI2009]植物大战僵尸
- 【bzoj1565】[NOI2009]植物大战僵尸
- BZOJ 1565: [NOI2009]植物大战僵尸(最大权闭合子图+拓扑排序)(最大权闭合子图介绍)
- BZOJ 1565 NOI 2009 Day2 T1 植物大战僵尸
- [BZOJ1565][NOI2009]植物大战僵尸(最大权闭合子图)
- Bzoj1565:[NOI2009]植物大战僵尸:拓扑排序+网络流
- 【BZOJ 1565】 [NOI2009]植物大战僵尸
- [题解]bzoj1565(NOI2009)植物大战僵尸