洛谷2805 [NOI2009]植物大战僵尸 (拓扑排序+最小割)
坚决抵制长题面的题目!
首先观察到这个题目中,我们会发现,我们对于原图中的保护关系(一个点右边的点对于这个点也算是保护)
相当于一种依赖。
那么不难看出这个题实际上是一个最大权闭合子图模型。
我们直接对于权值为负数的边,\(S\rightarrow now\),流量是\(-a[i][j]\),表示打掉他要花这么多的代价。
对于权值为正的边,\(now \rightarrow T\) ,流量是\(a[i][j]\),表示如果割掉这个边,表示放弃他的收益。
(这里之所以\(S和T\)不能反过来,因为我们跑最小割的时候,是要保证S到T不连通,所以你要让负的权值与S相连,才会让依赖关系有意义)
对于每个点,向他保护的点连边,边权为\(inf\)。表示这个关系不能打破。
同时一个点右边的点,向这个点连边,流量也是\(inf\),因为右边的点要比左边的点先被打。
最后的答案就是\(正权值的sum - 最小割\)(总的收益,减去花费和舍去的。)
那么建出来图,我们会发现其实这个是有问题的。
因为可能存在环的情况。
(\(A保护B,B保护A\))
那么应该怎么办呢?
我们发现如果存在一个环,那么环能保护到的点,以及再往后的点,都是无敌的!
所以合法的点,就是从起点开始,找到所有的满足起点到这个点的所有路径都不经过环的 点。
那么这个可以通过拓扑排序来实现。
qwq
只需要一开始先把所有的依赖关系,跑一遍拓扑排序。
然后选出来有效的点,再建图就ok
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 3010;
const int maxm = 2e6+1e2;
const int inf = 1e9;
int n,m,cnt=1;
int point[maxn],nxt[maxm],to[maxm],val[maxm];
int h[maxn],in[maxn];
int s,t;
int a[maxn][maxn];
int sum;
int num;
int dfn[maxn];
int tag[maxn];
vector<int> v[maxn];
void init()
{
cnt=1;
memset(point,0,sizeof(point));
memset(in,0,sizeof(in));
}
void add(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
in[y]++;
}
void addedge(int x,int y,int w)
{
nxt[++cnt]=point[x];
to[cnt]=y;
val[cnt]=w;
point[x]=cnt;
}
void insert(int x,int y,int w)
{
addedge(x,y,w);
addedge(y,x,0);
}
queue<int> q;
bool bfs(int s)
{
memset(h,-1,sizeof(h));
h[s]=0;
q.push(s);
while (!q.empty())
{
int x = q.front();
q.pop();
for (int i=point[x];i;i=nxt[i])
{
int p=to[i];
if (h[p]==-1 && val[i]>0)
{
h[p]=h[x]+1;
q.push(p);
}
}
}
if (h[t]==-1) return false;
return true;
}
int dfs(int x,int low)
{
if (x==t || low==0) return low;
int totflow=0;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (h[p]==h[x]+1 && val[i]>0)
{
int tmp = dfs(p,min(low,val[i]));
val[i]-=tmp;
val[i^1]+=tmp;
low-=tmp;
totflow+=tmp;
if (low==0) return totflow;
}
}
if (low>0) h[x]=-1;
return totflow;
}
int dinic()
{
int ans=0;
while (bfs(s))
{
ans=ans+dfs(s,inf);
}
return ans;
}
int getnum(int x,int y)
{
return (x-1)*m+y;
}
void tpsort()
{
while (!q.empty()) q.pop();
for (int i=1;i<=num;i++)
{
if (!in[i]) q.push(i),tag[i]=1,dfn[i]=1;
}
while (!q.empty())
{
int x = q.front();
q.pop();
for (int i=point[x];i;i=nxt[i])
{
int p=to[i];
in[p]--;
if (!in[p])
{
dfn[p]=dfn[x]+1;
q.push(p);
tag[p]=1;
}
}
}
}
int main()
{
n=read(),m=read();
num=n*m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
a[i][j]=read();
int num = read();
for (int k=1;k<=num;k++)
{
int x=read(),y=read();
x++,y++;
v[getnum(i,j)].pb(getnum(x,y));
add(getnum(i,j),getnum(x,y));
}
if (j!=m) add(getnum(i,j+1),getnum(i,j));
}
tpsort();
init();
s=maxn-10;
t=s+1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int now=getnum(i,j);
if(!tag[now]) continue;
if(a[i][j]>0) sum+=a[i][j];
for (int k=0;k<v[now].size();k++)
if (tag[v[now][k]]) insert(now,v[now][k],inf);
if (a[i][j]>0) insert(now,t,a[i][j]);
else insert(s,now,-a[i][j]);
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
int now = getnum(i,j);
int ri = getnum(i,j+1);
if (j==m) continue;
if (!tag[now] || !tag[ri]) continue;
if (dfn[ri]>dfn[now]) swap(now,ri);
insert(ri,now,inf);
}
}
cout<<sum-dinic();
return 0;
}
洛谷2805 [NOI2009]植物大战僵尸 (拓扑排序+最小割)的更多相关文章
- P2805 [NOI2009]植物大战僵尸 (拓扑排序 + 最小割)
题意:N*M的矩阵 每个点上都有一颗植物 僵尸只能从每一行的最右边向左进攻 每个植物有攻击范围 可以保护在攻击范围内的植物 同时每一颗植物也保护他左边的植物 摧毁每个植物能获得价值 如果这个植物被保护 ...
- 【BZOJ-1565】植物大战僵尸 拓扑排序 + 最小割
1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1972 Solved: 917[Submit][Statu ...
- 洛谷 P2805 [NOI2009]植物大战僵尸 解题报告
P2805 [NOI2009] 植物大战僵尸 题目描述 Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plan ...
- 洛谷$P2805\ [NOI2009]$植物大战僵尸 网络流
正解:网络流 解题报告: 传送门$QwQ$ 题面好长昂,,,我大概概括下$QwQ$?有个$n\cdot m$的网格,每个格子有一株植物,击溃一株植物$(x,y)$需要付出$S_{(x,y)}$的代价( ...
- 【bzoj1565】[NOI2009]植物大战僵尸 拓扑排序+最大权闭合图
原文地址:http://www.cnblogs.com/GXZlegend/p/6808268.html 题目描述 输入 输出 仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何 ...
- 2018.11.02 洛谷P2661 信息传递(拓扑排序+搜索)
传送门 按照题意模拟就行了. 先拓扑排序去掉不在环上面的点. 剩下的都是简单环了. 于是都dfsdfsdfs一遍求出最短的环就行. 代码: #include<bits/stdc++.h> ...
- 洛谷P3243 [HNOI2015]菜肴制作 拓扑排序+贪心
正解:拓扑排序 解题报告: 传送门! 首先看到它这个约束就应该要想到拓扑排序辣QwQ 首先想到的应该是用优先队列代替队列,按照节点编号排序 然后也很容易被hack:<5,1> 正解应为5, ...
- 【洛谷P4934】 礼物,拓扑排序
题目大意:给你$n$个不重复的数,其值域为$[0,2^k)$,问你至少需要将这$n$个数拆成多少个集合,使得它们互相不是对方的子集,并输出方案. 数据范围:$n≤10^6$,$k≤20$. $MD$我 ...
- BZOJ 1565 植物大战僵尸(拓扑排序+最大权闭合子图)
图中的保护关系就类似于最大权闭合子图.即你想杀x,你就一定要杀掉保护x的点,那么把x向保护它的点连边.那么题目就转化成了最大权闭合子图的问题. 但是这个图有点特殊啊... 考虑有环的情况,显然这个环以 ...
随机推荐
- Linux基础——安装以及常用命令
Linux基础--常用命令 1.安装Vmware 进入VMware官网: https://www.vmware.com/cn.html下载安装 镜像推荐网址下载:https://www.linux. ...
- 硬核! Github上 ,star超高的Java 开源项目分享给你!
Awsome JavaGreat Java project on Github(Github 上非常棒的 Java 开源项目). English Version 大家都知道 Github 是一个程序员 ...
- 基于Linux系统的MariaDB数据库的安装配置
数据库是指长期存储在计算机内.有组织的和可共享的数据集合.表是数据库存储数据的基本单位,一个表由若干个字段组成 MariaDB 数据库管理系统是 MySQL 的一个分支,主要由开源社区在维护,采用 G ...
- vue 监听父子组件传参,对象数据变化
watch:{ 组件传参的字段 :{ handler (newV, oldV){ 这里打印 newV, oldV 就可以看到数据变化了 } , immediate: true, // 重点 deep: ...
- NCNN优化实时面部关键点检测
效果图 演示手机为红米10X pro,可以实时跑人脸检测+关键点识别二个模型. 主要优化 上次看见有人讨论人脸检测与关键点识别,用的是opencv相关,于是想看下深度神经网络相关部分的进展,先选定了推 ...
- Mybatis(一)——HelloWorld
本人的博客一向保持"傻瓜式"的风格. 循序渐进学Mybatis,先konw how,再konw why.先整体,再细节! 本文不讲难懂的概念,先通过一个案例,希望读者跟着本文一步一 ...
- Python - 面向对象编程 - 小实战(3)
需求 房子(House)有户型.总面积.家具名称列表:新房子没有任何的家具 家具(HouseItem)有名字.占地面积 席梦思(bed) 占地 4 平米 衣柜(bed) 占地 2 平米 餐桌(bed) ...
- ABP VNext发布遇到的坑
本地调试没有问题,发布后通过Token调用其他API时,出现返回JSON中提示:Authorization failed! Given policy has not granted. 需要修改apps ...
- python库--tensorflow
方法 返回值类型 参数 说明 张量 .constant() Tensort 张量 实例t value 创建一个常量tensor dtype=None 输出类型 shape=None 返回tens ...
- GMAP.NET系列学习文档
http://www.cnblogs.com/enjoyeclipse/archive/2013/01/13/2858392.html http://www.cnblogs.com/luxiaoxun ...