BZOJ 1565 Luogu P2805 [NOI2009]植物大战僵尸 (Tarjan判环、最小割)
我: “立个flag 14点之前调完这题”
洛谷AC时间: 2019-06-24 14:00:16
实力打脸。。。
网络流板子从来写不对系列
题目链接: (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=1565
(luogu) https://www.luogu.org/problemnew/show/P2805
题解: 长得就那么像个最大权闭合子图啊。。。
\(i\)攻击\(j\)相当于如果想吃掉\(i\)必须吃掉\(j\), 另外如果吃掉\(i\)必须吃掉\(i\)右侧的点,最大权闭合子图。
但是可能有环,注意环并非要么全吃要么全不吃而是全都不能吃,所以用Tarjan提前判一下环,在环里的点和\(T\)连\(+\inf\)表示不能吃
时间复杂度\(O(MaxFlow(nm,(nm)^2))\).
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 602;
const int M = 362400;
const int INF = 1e8;
namespace MaxFlow
{
struct Edge
{
int v,w,nxt,rev;
} e[(M<<1)+3];
int fe[N+3];
int te[N+3];
int dep[N+3];
int que[N+3];
int n,en;
void addedge(int u,int v,int w)
{
en++; e[en].v = v; e[en].w = w;
e[en].nxt = fe[u]; fe[u] = en; e[en].rev = en+1;
en++; e[en].v = u; e[en].w = 0;
e[en].nxt = fe[v]; fe[v] = en; e[en].rev = en-1;
}
bool bfs()
{
for(int i=1; i<=n; i++) dep[i] = 0;
int head = 1,tail = 1; que[tail] = 1; dep[1] = 1;
while(head<=tail)
{
int u = que[head]; head++;
for(int i=fe[u]; i; i=e[i].nxt)
{
if(dep[e[i].v]==0 && e[i].w>0)
{
dep[e[i].v] = dep[u]+1;
tail++; que[tail] = e[i].v;
}
}
}
return dep[2]!=0;
}
int dfs(int u,int cur)
{
if(u==2) {return cur;}
int rst = cur;
for(int i=te[u]; i; i=e[i].nxt)
{
if(dep[e[i].v]==dep[u]+1 && e[i].w>0 && rst>0)
{
int flow = dfs(e[i].v,min(rst,e[i].w));
if(flow>0)
{
e[i].w-=flow; e[e[i].rev].w += flow; rst-=flow;
if(e[i].w>0) {te[u] = i;}
if(rst==0) {return cur;}
}
}
}
if(cur==rst) {dep[u] = 0;}
return cur-rst;
}
int dinic(int _n)
{
n = _n;
int ret = 0;
while(bfs())
{
for(int i=1; i<=n; i++) te[i] = fe[i];
ret += dfs(1,INF);
}
return ret;
}
}
namespace Tarjan
{
struct Edge
{
int v,nxt;
} e[M+3];
int fe[N+3];
int dfn[N+3],low[N+3],stk[N+3];
bool instk[N+3];
bool inscc[N+3];
int n,en,cnt,tp;
void addedge(int u,int v)
{
en++; e[en].v = v;
e[en].nxt = fe[u]; fe[u] = en;
}
void dfs(int u)
{
cnt++; dfn[u] = low[u] = cnt; tp++; stk[tp] = u; instk[u] = true;
for(int i=fe[u]; i; i=e[i].nxt)
{
if(!dfn[e[i].v])
{
dfs(e[i].v);
low[u] = min(low[u],low[e[i].v]);
}
else if(instk[e[i].v])
{
low[u] = min(low[u],low[e[i].v]);
}
}
if(low[u]>=dfn[u])
{
if(stk[tp]!=u) {inscc[u] = true;}
while(stk[tp]!=u)
{
inscc[stk[tp]] = true;
instk[stk[tp]] = false;
stk[tp] = 0; tp--;
}
stk[tp] = 0; tp--; instk[u] = false;
}
}
void work(int _n)
{
n = _n;
for(int i=1; i<=n; i++)
{
if(!dfn[i]) {dfs(i);}
}
}
}
int n,m;
int getid(int x,int y) {return x*m+y+3;}
int main()
{
scanf("%d%d",&n,&m); int ans = 0;
for(int i=1; i<=n*m; i++)
{
int x; scanf("%d",&x);
if(x>0) {MaxFlow::addedge(1,i+2,x); ans += x;}
else if(x<0) {MaxFlow::addedge(i+2,2,-x);}
scanf("%d",&x);
while(x--)
{
int y,z; scanf("%d%d",&y,&z); int pos = getid(y,z);
MaxFlow::addedge(pos,i+2,INF);
Tarjan::addedge(pos-2,i);
}
if(i%m!=0)
{
MaxFlow::addedge(i+2,i+3,INF);
Tarjan::addedge(i,i+1);
}
}
Tarjan::work(n*m);
for(int i=1; i<=n*m; i++)
{
if(Tarjan::inscc[i])
{
MaxFlow::addedge(i+2,2,INF);
}
}
int tmp = MaxFlow::dinic(n*m+2);
ans -= tmp;
printf("%d\n",ans);
return 0;
}
BZOJ 1565 Luogu P2805 [NOI2009]植物大战僵尸 (Tarjan判环、最小割)的更多相关文章
- 洛谷2805 [NOI2009]植物大战僵尸 (拓扑排序+最小割)
坚决抵制长题面的题目! 首先观察到这个题目中,我们会发现,我们对于原图中的保护关系(一个点右边的点对于这个点也算是保护) 相当于一种依赖. 那么不难看出这个题实际上是一个最大权闭合子图模型. 我们直接 ...
- 【BZOJ 3232】圈地游戏 二分+SPFA判环/最小割经典模型
最小割经典模型指的是“一堆元素进行选取,对于某个元素的取舍有代价或价值,对于某些对元素,选取后会有额外代价或价值”的经典最小割模型,建立倒三角进行最小割.这个二分是显然的,一开始我也是想到了最小割的那 ...
- 洛谷 P2805 [NOI2009]植物大战僵尸 解题报告
P2805 [NOI2009] 植物大战僵尸 题目描述 Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plan ...
- BZOJ 1565 / P2805 [NOI2009]植物大战僵尸 (最大权闭合子图 最小割)
题意 自己看吧 BZOJ传送门 分析 - 这道题其实就是一些点,存在一些二元限制条件,即如果要选uuu则必须选vvv.求得到的权值最大是多少. 建一个图,如果选uuu必须选vvv,则uuu向vvv连边 ...
- P2805 [NOI2009]植物大战僵尸 + 最大权闭合子图 X 拓扑排序
传送门:https://www.luogu.org/problemnew/show/P2805 题意 有一个n * m的地图,你可以操纵僵尸从地图的右边向左边走,走的一些地方是有能量值的,有些地方会被 ...
- 洛谷$P2805\ [NOI2009]$植物大战僵尸 网络流
正解:网络流 解题报告: 传送门$QwQ$ 题面好长昂,,,我大概概括下$QwQ$?有个$n\cdot m$的网格,每个格子有一株植物,击溃一株植物$(x,y)$需要付出$S_{(x,y)}$的代价( ...
- BZOJ 2039 / Luogu P1791 [2009国家集训队]employ人员雇佣 (最小割)
题面 BZOJ传送门 Luogu传送门 分析 考虑如何最小割建图,因为这仍然是二元关系,我们可以通过解方程来确定怎么建图,具体参考论文 <<浅析一类最小割问题 湖南师大附中 彭天翼> ...
- P2805 [NOI2009]植物大战僵尸(最小割+拓扑排序)
题意: n*m的矩阵,每个位置都有一个植物.每个植物都有一个价值(可以为负),以及一些它可以攻击的位置.从每行的最右面开始放置僵尸,僵尸从右往左行动,当僵尸在植物攻击范围内时会立刻死亡.僵尸每到一个位 ...
- P2805 [NOI2009]植物大战僵尸 (拓扑排序 + 最小割)
题意:N*M的矩阵 每个点上都有一颗植物 僵尸只能从每一行的最右边向左进攻 每个植物有攻击范围 可以保护在攻击范围内的植物 同时每一颗植物也保护他左边的植物 摧毁每个植物能获得价值 如果这个植物被保护 ...
随机推荐
- 【168】ENVI入门系列
参考:ENVI-IDL中国的博客 [ENVI入门系列]01.ENVI产品简介与入门 [ENVI入门系列]02.自定义坐标系(北京54.西安80.2000坐标系) [ENVI入门系列]03.基于自带定位 ...
- asp.net 4.0 尚未在服务商注册 您需要手动将web服务器配置为 ASP.NET4.0,这样您的网站才能正常进行。
VS2010打开项目出现的此问题 电脑先安装VS2010 然后安装VS2010 SP1补丁.然后安装VS2015 后来又安装了Framework4.6.1 用网上搜索到的平常方法无法解决此问题. 最后 ...
- vue用户登录状态判断
之前项目中用来判断是否登录我写了多种方案,但是最终只有一个方案是比较好的,这篇博客就是分享该方案; 先说基本要求: 项目中的登录状态是依据服务器里的状态来作为判断依据; 每一个需要登录后才能操作的接口 ...
- 【第三届强网杯】write up
一,鲲or鳗orGame 从浏览器里拿到game.gb 用 VisualBoyAdvance ,搜索内存变量,然后改变量就完事了,但是改变量他们说直接利用添加代码功能有bug,所以要在工具里的内存查看 ...
- mysql 的索引hash和b+tree 区别
索引hash相当于数组,键值对组合,对于id = 6或者status= 2这样条件查询,但是对于id>12等这样,用btree索引最好.
- P4451 [国家集训队]整数的lqp拆分
#include <bits/stdc++.h> using namespace std; typedef long long LL; inline LL read () { LL res ...
- EasyUI系列学习(六)-Tooltip(提示框)
一.创建组件 0.Tooltip不依赖其他组件 1.使用class加载 <a href="#" class="easyui-tooltip" title= ...
- java list遍历三种方法
JSONArray jsonArray = new JSONArray(); jsonArray.add("1"); jsonArray.add("2"); j ...
- Scala-基础-运算符
import junit.framework.TestCase /** * 运算符 */ class Demo3 extends TestCase { def test_+ { var x = 10; ...
- Framework7首页隐藏navbar
f7首页隐藏navbar其他页面显示navbar 帮别人解决问题,自己也记录一下, 首页.navbar加.navbar-hidden, 首页.page加.no-navbar, 如果首页有.navbar ...