BZOJ 1565 NOI2009 植物大战僵尸 topo+最小割(最大权闭合子图)
题目链接:https://www.luogu.org/problemnew/show/P2805(bzoj那个实在是有点小小的辣眼睛。。。我就把洛谷的丢出来吧。。。)
题意概述:给出一张有向图,这张有向图上的每个点都有一个点权,想要访问某个点必须要先访问这个点所能够访问(遍历)到的所有点,在访问到一个点之后将会得到这个点的权值(可正可负)。问访问这张图可以得到的最大点权和。
原题说过来说过去实际上是描述了一个植物之间的保护关系,也就是说明了植物之间的先后访问顺序之间的关系。可以描述为要“要访问点a,先要访问点b”这样的形式,并且题意总结出来之后很容易发现这就是一个最大权闭合子图问题。
但是我们注意到原题给出的并不一定是一个DAG图。事实上,可能有些植物互相保护,导致僵尸只能当炮灰。。。。于是我们需要把环去掉,这一步可以topo序解决,只是不是真的topo,而是从入度为0的点开始的(访问所有可以不经过环就可以访问到的点)。
然后就是直接网络流上跑最大权闭合子图。但是值得注意的是最大权闭合子图是满足一种推导关系,即上面的“要访问点a,先要访问先b”这种关系形成的一条有向边,容量为inf,因为要满足这样的推导关系,所以上面求topo的时候连的边要反过来。然后原点向所有点权为正的边连一条边,容量为点权;所有点权为负的点向汇点连一条边,容量为点权的相反数。在求最小割的时候如果一条边被割掉,那么意义就是做出选择(S有关的边是不选这个点,T有关的边是选了这个点)之后付出的代价。
最后只需要把所有的正权点权值相加(可以得到的最大收益),减去最小割(付出的最小代价),就是我们最终获得的最大收益。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int MAXN=;
const int MAXM=; int N,M,sco[MAXN][MAXM];
struct XY{ int x,y; };
vector<XY>att[MAXN][MAXM];
struct graph{
static const int maxn=;
static const int maxm=;
struct edge{ int from,to,next; }E[maxm];
int n,first[maxn],np,rd[maxn],topo[maxn];
graph(){ np=; }
void add_edge(int u,int v){
E[++np]=(edge){u,v,first[u]};
first[u]=np;
}
void topo_sort(){
queue<int>q;
for(int i=;i<=n;i++)
if(!rd[i]) topo[i]=,q.push(i);
while(!q.empty()){
int i=q.front(); q.pop();
for(int p=first[i];p;p=E[p].next){
int j=E[p].to;
if(--rd[j]==) topo[j]=,q.push(j);
}
}
}
}gp;
struct NET{
static const int maxn=;
static const int maxm=;
static const int inf=1e7+;
struct edge{ int from,to,next,cap,flow; }E[maxm<<];
int S,T,n,first[maxn],np,fl[maxn],gap[maxn],d[maxn],cur[maxn];
NET(){ np=; }
void add_edge(int u,int v,int w){
E[++np]=(edge){u,v,first[u],w,};
first[u]=np;
E[++np]=(edge){v,u,first[v],,};
first[v]=np;
}
void BFS(){
queue<int>q;
for(int i=;i<=n;i++) d[i]=n;
d[T]=; q.push(T);
while(!q.empty()){
int i=q.front(); q.pop();
for(int p=first[i];p;p=E[p].next){
int j=E[p].to,pp=(p-^)+;
if(E[pp].cap>E[pp].flow&&d[j]==n) d[j]=d[i]+,q.push(j);
}
}
}
int augment(){
int now=T,flow=inf;
while(now!=S){
flow=min(flow,E[fl[now]].cap-E[fl[now]].flow);
now=E[fl[now]].from;
}
now=T;
while(now!=S){
E[fl[now]].flow+=flow,E[(fl[now]-^)+].flow-=flow;
now=E[fl[now]].from;
}
return flow;
}
int ISAP(){
memcpy(cur,first,sizeof(first));
BFS();
for(int i=;i<=n;i++) gap[d[i]]++;
int now=S,flow=;
while(d[S]<n){
if(now==T) flow+=augment(),now=S;
bool ok=;
for(int p=cur[now];p;p=E[p].next){
int j=E[p].to;
if(E[p].cap>E[p].flow&&d[j]+==d[now]){
ok=,fl[j]=cur[now]=p,now=j;
break;
}
}
if(!ok){
int minl=n;
for(int p=first[now];p;p=E[p].next){
int j=E[p].to;
if(E[p].cap>E[p].flow&&d[j]+<minl) minl=d[j]+;
}
if(--gap[d[now]]==) break;
gap[d[now]=minl]++;
cur[now]=first[now];
if(now!=S) now=E[fl[now]].from;
}
}
return flow;
}
}net; void data_in()
{
scanf("%d%d",&N,&M);
int w,x,y;
for(int i=;i<=N;i++)
for(int j=;j<=M;j++){
scanf("%d%d",&sco[i][j],&w);
for(int k=;k<=w;k++){
scanf("%d%d",&x,&y);
att[i][j].push_back((XY){x+,y+});
}
}
}
int idx(int x,int y){ return (x-)*M+y; }
void build_net()
{
for(int i=;i<=N;i++)
for(int j=;j<=M;j++){
int id=idx(i,j);
for(int k=;k+j<=M;k++){
gp.add_edge(id+k,id);
gp.rd[id]++;
}
for(int k=;k<att[i][j].size();k++){
int _id=idx(att[i][j][k].x,att[i][j][k].y);
gp.add_edge(id,_id); gp.rd[_id]++;
}
}
gp.n=N*M; gp.topo_sort();
for(int p=;p<=gp.np;p++){
int x=gp.E[p].from,y=gp.E[p].to;
if(gp.topo[x]&&gp.topo[y]) net.add_edge(y,x,net.inf);
}
net.n=N*M+,net.S=net.n-,net.T=net.n;
for(int i=;i<=N;i++)
for(int j=;j<=M;j++) if(gp.topo[idx(i,j)]){
if(sco[i][j]>) net.add_edge(net.S,idx(i,j),sco[i][j]);
else if(sco[i][j]<) net.add_edge(idx(i,j),net.T,-sco[i][j]);
}
}
void work()
{
build_net();
int sum=;
for(int i=;i<=N;i++)
for(int j=;j<=M;j++)
if(sco[i][j]>&&gp.topo[idx(i,j)]) sum+=sco[i][j];
printf("%d\n",sum-net.ISAP());
}
int main()
{
data_in();
work();
return ;
}
BZOJ 1565 NOI2009 植物大战僵尸 topo+最小割(最大权闭合子图)的更多相关文章
- [BZOJ1565][NOI2009]植物大战僵尸-[网络流-最小割+最大点权闭合子图+拓扑排序]
Description 传送门 Solution em本题知识点是用网络流求最大点权闭合子图. 闭合图定义:图中任何一个点u,若有边u->v,则v必定也在图中. 建图:运用最小割思想,将S向点权 ...
- b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子图
b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子 题意:n*m个植物,每个植物有分数(可正可负),和能保护植物的位置.只能从右往左吃,并且不能吃正被保护着的,可以一个不吃,求 ...
- BZOJ1565 [NOI2009]植物大战僵尸(拓扑排序 + 最大权闭合子图)
题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=1565 Description Input Output 仅包含一个整数,表示可以 ...
- bzoj 1565 [NOI2009]植物大战僵尸 解题报告
1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2161 Solved: 1000[Submit][Stat ...
- BZOJ 1565: [NOI2009]植物大战僵尸( 最小割 )
先拓扑排序搞出合法的, 然后就是最大权闭合图模型了.... --------------------------------------------------------------------- ...
- Bzoj 1565: [NOI2009]植物大战僵尸 最大权闭合图,拓扑排序
题目: http://cojs.tk/cogs/problem/problem.php?pid=410 410. [NOI2009] 植物大战僵尸 ★★★ 输入文件:pvz.in 输出文件:p ...
- BZOJ 1565 [NOI2009]植物大战僵尸 | 网络流
传送门 BZOJ 1565 题解 这道题也是个经典的最大权闭合子图-- 复习一下最大权闭合子图是什么? 就是一个DAG上,每个点有个或正或负的点权,有的点依赖于另外一些点(如果选这个点,则被依赖点必选 ...
- bzoj 1565 [NOI2009]植物大战僵尸【tarjan+最大权闭合子图】
一上来以为是裸的最大权闭合子图,上来就dinic -然后没过样例.不得不说样例还是非常良心的给了一个强连通分量,要不然就WA的生活不能自理了 然后注意到有一种特殊情况:每个植物向他保护的植物连边(包括 ...
- BZOJ 1565: [NOI2009]植物大战僵尸(网络流+缩点)
传送门 解题思路 最大权闭合子图.但是要注意一些细节,假如有一堆植物形成一个环,那么这些植物都是无敌的,并且他们保护的植物是无敌的,他们保护的保护的植物是无敌 的.所以要缩点,然后拓扑排序一次判无敌, ...
随机推荐
- MVVM及框架的双向绑定
MVVM由以下三个内容组成 View:视图模板 Model:数据模型 ViewModel:作为桥梁负责沟通View和Model,自动渲染模板 在JQuery时期,如果需要刷新UI时,需要先取到对应的D ...
- 话说"登录页面"怎么测试
今天无聊突然想起web登录页面怎么测试,看似简单的问题杀机重重,怎么说呢,一般没有测试思维的人说简单啦,主要有以下几点 .1.账号密码框输入正确的a-z,A-Z,0-9字符,特殊的字符组合测试.2.账 ...
- Oracle 11g行字段拼接WMSYS.WM_CONCAT问题Not A LOB
Oracle 11g行字段拼接WMSYS.WM_CONCAT问题Not A LOB 一.问题出现 项目中的某个查询需要将表中某个字段不重复地拼接起来,百度得到该函数WMSYS.WM_CONCAT(字段 ...
- Linux修改时区以及同步时间
Centos7为例:修改时区 timedatectl list-timezones |grep Shanghai #查找中国时区的完整名称 Asia/Shanghai timedatectl set- ...
- React中需要多个倒计时的问题
最近有一个需求是做一个闪购列表,列表中每一个商品都有倒计时,如果每一个倒计时都去生成一个setTimeout的话,一个页面就会有很多定时器,感觉这种做法不是非常好,于是换了一个思路. 思路是这样的,一 ...
- Configuration Alias
第一个里程碑 ---- 查看系统别名 [root@xilong ~]# alias alias cp='cp -i' alias egrep='egrep --color=auto' alias fg ...
- vue项目全局使用axios
共有三种方法: 1.结合 vue-axios使用 首先在主入口文件main.js中引用 import axios from 'axios' import VueAxios from 'vue-axio ...
- PHP导出数据到表格的实例
我发现最近的项目需要导出Excel表的页面非常的多,想来这个也是我们常用的功能了,现在我可以很熟练的导出了,但是记得当时自己第一次导出时还是绕了一些弯路的,那么现在我就来记录下我这次用exshop框架 ...
- MySQL快速生成连续整数
很多时候需要用到连续的id进行数据对比,如判断是否连续等问题.那么,生成连续整数的方式有多种,首先容易想到的是逐步循环,如果想生成1kw条记录,则需要循环1kw次进行插入,那么有没有其他方式呢,效率相 ...
- Mysqldump自定义导出n条记录
很多时候DBA需要导出部分记录至开发.测试环境,因数据量需求较小,如果原库的记录多,且表数量也多,在用mysqldump命令导出时可以添加一个where参数,自定义导出n条记录,而不必全量导出. 示例 ...