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的矩阵 每个点上都有一颗植物 僵尸只能从每一行的最右边向左进攻 每个植物有攻击范围 可以保护在攻击范围内的植物 同时每一颗植物也保护他左边的植物 摧毁每个植物能获得价值 如果这个植物被保护 ...
随机推荐
- JavaSwing输入对话框,点击取消抛出异常的解决方法
在做产品管理系统的时候,遇到一个问题: 在得到一个输入框对话框的时候 String textPrice = JOptionPane.showInputDialog("请输入要调整的价格增(减 ...
- bzoj 1635: [Usaco2007 Jan]Tallest Cow 最高的牛【差分】
s[i]为差分后的"i这头牛前有几头比它高",计算答案的时候加成前缀和,假设第一头最高减一下即可 用map记录一下被加过的区间,避免重复 #include<iostream& ...
- 洛谷P4158 [SCOI2009]粉刷匠
传送门 设$dp[i][j][k][0/1]$表示在涂点$(i,j)$,涂了$k$次,当前点的颜色是否对,最多能刷对多少个格子 首先换行的时候肯定得多刷一次 然后是如果和前一个格子颜色相同,那么当前点 ...
- 微信扫码下载APK遮罩提示示例
由于微信的限制,应用文件在内置浏览器中下载全部被屏蔽掉,造成很多人用微信扫描二维码下载时,界面显示一片空白,容易误导以为在下载呢.按照当前主流习惯,做一个提示用户在浏览器中打开下载的遮罩.网上很多现成 ...
- 2017 Pycharm激活码
BIG3CLIK6F-eyJsaWNlbnNlSWQiOiJCSUczQ0xJSzZGIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...
- 构造+暴力 Codeforces Round #283 (Div. 2) B. Secret Combination
题目传送门 /* 构造+暴力:按照题目意思,只要10次加1就变回原来的数字,暴力枚举所有数字,string大法好! */ /************************************** ...
- ACM_01背包2
背包4 Time Limit: 2000/1000ms (Java/Others) Problem Description: 有n个重量和价值分别为Wi,Vi的物品,现从这些物品中挑选出总量不超过W的 ...
- pyinstaller打包报错:AttributeError: 'str' object has no attribute 'items'
导致原因和python多数奇奇怪怪的问题一样,依赖包的版本问题. 解决办法: 对setuptools这个包进行升级,链接在这里 https://pypi.org/project/setuptools/ ...
- 待销售分拣单App数据推送
管理待分拣商品的App的显示操作
- phpcms标签第三弹
{CHARSET} -------------------------------------字符集 (gbk或者utf-8) {if isset($SEO['title']) && ...