坚决抵制长题面的题目!

首先观察到这个题目中,我们会发现,我们对于原图中的保护关系(一个点右边的点对于这个点也算是保护)
相当于一种依赖。

那么不难看出这个题实际上是一个最大权闭合子图模型。

我们直接对于权值为负数的边,\(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;
}

转载于:https://www.cnblogs.com/yimmortal/p/10189176.html

洛谷2805 [NOI2009]植物大战僵尸 (拓扑排序+最小割)相关推荐

  1. 【bzoj1565】[NOI2009]植物大战僵尸 拓扑排序+最大权闭合图

    原文地址:http://www.cnblogs.com/GXZlegend/p/6808268.html 题目描述 输入 输出 仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何 ...

  2. 洛谷P3953 逛公园(dp 拓扑排序)

    题意 题目链接 Sol 去年考NOIP的时候我好像连最短路计数都不会啊qwq.. 首先不难想到一个思路,\(f[i][j]\)表示到第\(i\)个节点,与最短路之差长度为\(j\)的路径的方案数 首先 ...

  3. 2018.11.02 洛谷P2661 信息传递(拓扑排序+搜索)

    传送门 按照题意模拟就行了. 先拓扑排序去掉不在环上面的点. 剩下的都是简单环了. 于是都dfsdfsdfs一遍求出最短的环就行. 代码: #include<bits/stdc++.h> ...

  4. 洛谷 P1983 车站分级(拓扑排序)

    https://www.luogu.com.cn/problem/P1983 思路 对于每一趟车,将其经过的车站中,停靠的和不停靠的连一条边,注意边的去重,要双向标记,不然有个点会超时,这样拓扑排序递 ...

  5. 洛谷P1983 车站分级(拓扑排序)

    [题目描述] 一条单向的铁路线上,依次有编号为 1 , 2 , - , n 1,2,\dots ,n 1,2,-,n的 n n n个火车站.每个火车站都有一个级别,最低为 1 1 1级.现有若干趟车次 ...

  6. 洛谷P3243 [HNOI2015]菜肴制作——拓扑排序

    题目:https://www.luogu.org/problemnew/show/P3243 正向按字典序拓扑排序很容易发现是不对的,因为并不是序号小的一定先做: 但若让序号大的尽可能放在后面,则不会 ...

  7. 洛谷 - P2944 [USACO09MAR]Earthquake Damage 2 G(最小割)

    题目连接:点击查看 题目大意:给出一个 p 个点 c 条边的无向图,设置点 1 为基地,现在有 n 个点表示自己没有被摧毁,但无法与基地相连,现在问最少摧毁多少个点可以使得满足条件 题目分析:最小割, ...

  8. BZOJ1565[NOI2009]植物大战僵尸——最大权闭合子图+拓扑排序

    题目描述 Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻.该款游戏包含多 ...

  9. 洛谷P2805 [NOI2009] 植物大战僵尸

    [NOI2009]植物大战僵尸 题面 洛谷 题解 先扯一些无关的,最近怀旧重新玩了玩植物大战僵尸,然后发现打到夜晚池塘的时候矿工僵尸发现很难处理于是回来刷了刷题... 看到洛谷上正好有道植物大战僵尸就 ...

  10. BZOJ 1565 Luogu P2805 [NOI2009]植物大战僵尸 (Tarjan判环、最小割)

    我: "立个flag 14点之前调完这题" 洛谷AC时间: 2019-06-24 14:00:16 实力打脸... 网络流板子从来写不对系列 题目链接: (BZOJ) https: ...

最新文章

  1. 教程,使用YCSB测试MYSQL数据库,获取千万条测试后的数据
  2. php动态数组的存储过程,PHP数组作为存储过程的输入
  3. vue实现移动端圆形旋钮插件
  4. c c mySQL机票设计_期末课程设计之 c++操作mysql完成机票预订系统(vc 6.0配置mysql环境)...
  5. hashtable与HashMap区别
  6. 57张PPT彻底搞清楚区块链技术。。
  7. C++的extern关键字
  8. WIN10 vagrant和virtualbox虚拟机和一键搭建lnmp环境配置thinkphp虚拟主机
  9. 树莓派Java程序运行_树莓派上Java程序作为linux服务并开机自动启动
  10. Visual Studio 起始页中不显示最近使用的项目的解决办法
  11. Redis集群方案应该怎么做?都有哪些方案?
  12. python错误集合
  13. 第四章:FLASK结构拆分和循环引入问题
  14. python 快速排名发包_2019年SEO快速排名发包技术及原理 - 立金哥
  15. html 倒计时小工具
  16. 计算机中常见的循环,电脑系统提示数据错误循环冗余检查的解决方法教程[多图]...
  17. Beaglebone Black - 准备
  18. OpenGL圆柱面绘制贴图
  19. C语言逻辑类型与运算
  20. MySQL隔离级别的底层理解(MVCC+锁)

热门文章

  1. Python 字典(Dictionary) items()方法
  2. linux屏幕获取分辨率方法,Android 获取屏幕的分辨率
  3. 广州元宇宙10条(附pdf下载地址)
  4. android圆盘布局,Android绘制圆盘控件
  5. JavaWeb学习(二)Maven
  6. 计算机名汉字 oracle,修改计算机名对ORACLE的影像
  7. java ctr v,解决 ctrol c ctrol v 复制 粘贴 不好用的问题 只复制一次的问题
  8. Redis 常见问题 与 常见错误
  9. MySQL sql语句字段截取前几位,后几位等
  10. 获取ip地址 域名获取与解析