题目链接: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+最小割(最大权闭合子图)的更多相关文章

  1. [BZOJ1565][NOI2009]植物大战僵尸-[网络流-最小割+最大点权闭合子图+拓扑排序]

    Description 传送门 Solution em本题知识点是用网络流求最大点权闭合子图. 闭合图定义:图中任何一个点u,若有边u->v,则v必定也在图中. 建图:运用最小割思想,将S向点权 ...

  2. b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子图

    b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子 题意:n*m个植物,每个植物有分数(可正可负),和能保护植物的位置.只能从右往左吃,并且不能吃正被保护着的,可以一个不吃,求 ...

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

    题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=1565 Description Input Output 仅包含一个整数,表示可以 ...

  4. bzoj 1565 [NOI2009]植物大战僵尸 解题报告

    1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2161  Solved: 1000[Submit][Stat ...

  5. BZOJ 1565: [NOI2009]植物大战僵尸( 最小割 )

    先拓扑排序搞出合法的, 然后就是最大权闭合图模型了.... --------------------------------------------------------------------- ...

  6. Bzoj 1565: [NOI2009]植物大战僵尸 最大权闭合图,拓扑排序

    题目: http://cojs.tk/cogs/problem/problem.php?pid=410 410. [NOI2009] 植物大战僵尸 ★★★   输入文件:pvz.in   输出文件:p ...

  7. BZOJ 1565 [NOI2009]植物大战僵尸 | 网络流

    传送门 BZOJ 1565 题解 这道题也是个经典的最大权闭合子图-- 复习一下最大权闭合子图是什么? 就是一个DAG上,每个点有个或正或负的点权,有的点依赖于另外一些点(如果选这个点,则被依赖点必选 ...

  8. bzoj 1565 [NOI2009]植物大战僵尸【tarjan+最大权闭合子图】

    一上来以为是裸的最大权闭合子图,上来就dinic -然后没过样例.不得不说样例还是非常良心的给了一个强连通分量,要不然就WA的生活不能自理了 然后注意到有一种特殊情况:每个植物向他保护的植物连边(包括 ...

  9. BZOJ 1565: [NOI2009]植物大战僵尸(网络流+缩点)

    传送门 解题思路 最大权闭合子图.但是要注意一些细节,假如有一堆植物形成一个环,那么这些植物都是无敌的,并且他们保护的植物是无敌的,他们保护的保护的植物是无敌 的.所以要缩点,然后拓扑排序一次判无敌, ...

随机推荐

  1. Kinect骨架数据

  2. Unity3d Gis 坐标转换

    最近在做unity3d与Gis结合的项目,最基本的就是坐标的转换问题,比如把经纬度为(166.23.9.27 , 39.55.15.74) 转换到unity里面成相应的位置点,废话不多说 上代码: u ...

  3. ProjectServer任务审批后自动发布

    我们知道ProjectServer汇报工时的顺序是这样: 1.项目成员打开自己的时间表,选择要汇报的任务,在汇报工时栏填写实际工时. 2.汇报工时后点击保存. 3.将汇报工时的任务提交给项目经理. 4 ...

  4. 一款查询天气的WebApp

    一.WebApp介绍 1.初始界面 2.搜索结果页面 二.项目代码 1.项目目录 --------app ----------app.component.ts ----------app.compon ...

  5. aes 加密,解密(2)

    JavaScript加密,解密 1,此为AES加密后,转换为16进制编码 var encodePwd = function (data,key){ var keyHex = CryptoJS.enc. ...

  6. string类中字符的大小写转换

    今天做一道题,要用string类,涉及大小写转换,查看了C++文档,string类没有提供这样的方法,只好自己写. 之后是想到一个比较笨的方法,我把string当成一个容器,然后用迭代器一个一个来替换 ...

  7. leetcode笔记(八)263. Ugly Number

    题目描述 Write a program to check whether a given number is an ugly number. Ugly numbers are positive nu ...

  8. 使用Python对Csv文件操作

    csv是Comma-Separated Values的缩写,是用文本文件形式储存的表格数据,比如如下的表格: 就可以存储为csv文件,文件内容是: No.,Name,Age,Score 1,mayi, ...

  9. JAVA日期类图解

  10. 使用NPOI快速导出导入Excel

    这两天做项目需要导入导出EXCEL,是基于NPOI的封装,设计思路是使用DataTable,然后导出一个和DataTable一模一样的Excel表出来 github地址:https://github. ...