zoukankan      html  css  js  c++  java
  • BZOJ 1565 植物大战僵尸 最大权闭合子图+网络流

    题意:

      植物大战僵尸,一个n*m的格子,每 个格子里有一个植物,每个植物有两个属性:

      (1)价值;

      (2)保护集合,也就是这个植物可以保护矩阵中的某些格子。

      现在你是僵尸,你每次只能从(i,m) 格子进入,从右向左进攻。若一个格子是被保护的那么你是不能进入的。每进入一个格子则吃掉该格子的植物并得到其价值(价值有可能是负的),可以中途返回。问可以得到的最大价值是多少?

    分析:

      这是一道比较真实的题目。(真打游戏的时候应该也是这种景象吧)

      首先我们复习一下最大权闭合子图的特质。

      有一个有向图,每一个点都有一个权值(可以为正或负或0),选择一个权值和最大的子图,使得每个点的后继都在子图里面,这个子图就叫最大权闭合子图。

      上面这句话我们要提炼出一个极其重要的信息:如果我们选择一个点,那就必须选择它的所有后继。

      凡是题目中隐含着这样的条件的,我们都可以往最大权闭合子图方向去想一想。

      像这道题,每个植物可以保护一些其他的植物。那就意味着,如果我们想要选择一个植物,我们必须首先把所有保护它的植物都选掉。

      这样,我们就可以建图,对于一个点x,假如有点y可以保护点x,那么我们就连一条x—>y的边,注意,边的方向和保护的方向是相反的。

      (这里有好多题解都不是这么说的,或许另有高论?)

      还隐含着一个条件:右边的始终植物保护着左边的植物(对吧?植物大战僵尸里是这样的吧,所以诞生了高坚果)

      我们建图,跑最大权闭合子图就好了吗?

      并不是……

      因为环是无敌的……???!!!

      如果在保护关系中出现了环,那么你选任何一个,都是被保护的。

      所以我们拓扑,把环的影响取消掉,再跑最大权闭合子图的恶意……

      从源点s向每个正权点连一条容量为权值的边,每个负权点向汇点t连一条容量为权值的绝对值的边,有向图原来的边容量全部为无限大答案为正权值之和-最小割

    代码:

     1 #include<bits/stdc++.h>
     2 #define ms(a,x) memset(a,x,sizeof(a))
     3 using namespace std;int tot=0,n,m,sm=0;
     4 const int N=2005,inf=0x3f3f3f3f;
     5 struct node{int y,z,nxt;}e[N*400];
     6 int h[N],c=1,q[N],in[N],S,T,d[N],a[N],ans=0;
     7 void add(int x,int y,int z){in[x]++;
     8     e[++c]=(node){y,z,h[x]};h[x]=c;
     9     e[++c]=(node){x,0,h[y]};h[y]=c;
    10 } bool bfs(){
    11     for(int i=S;i<=T;i++) 
    12     if(d[i]!=-2) d[i]=-1;
    13     int f=1,t=0;d[S]=1;q[++t]=S;
    14     while(f<=t){
    15         int x=q[f++];
    16         for(int i=h[x],y;i;i=e[i].nxt)
    17         if(d[y=e[i].y]==-1&&e[i].z)
    18         d[y]=d[x]+1,q[++t]=y;
    19     } return (d[T]>0);
    20 } int dfs(int x,int f){
    21     if(x==T) return f;int w,tmp=0;
    22     for(int i=h[x],y;i;i=e[i].nxt)
    23     if(d[y=e[i].y]==d[x]+1&&e[i].z){
    24         w=dfs(y,min(e[i].z,f-tmp));
    25         if(!w) d[y]=-1;e[i].z-=w;
    26         e[i^1].z+=w;tmp+=w;
    27         if(tmp==f) return f;
    28     } return tmp;
    29 } void solve(){
    30     while(bfs()) tot+=dfs(S,inf);
    31 } int main(){
    32     scanf("%d%d",&n,&m);S=0;T=n*m+1;
    33     for(int i=1,tmp;i<=n*m;i++){
    34         scanf("%d",&a[i]);
    35         a[i]>0?add(S,i,a[i]):add(i,T,-a[i]);
    36         scanf("%d",&tmp);while(tmp--){
    37             int x,y;scanf("%d%d",&x,&y);
    38             add(x*m+y+1,i,inf);
    39         } if(i%m) add(i,i+1,inf);
    40     } int f=1,t=0;//图是反着建的,拓扑要倒过来 
    41     for(int i=S;i<=T;d[i]=-2,i++)
    42     if(!in[i]) q[++t]=i; 
    43     while(f<=t){
    44         int x=q[f++];d[x]=0;
    45         if(a[x]>0) sm+=a[x];
    46         for(int i=h[x];i;i=e[i].nxt)
    47         if(i&1)if(!--in[e[i].y]) q[++t]=e[i].y;
    48     } solve();
    49     printf("%d
    ",sm-tot);return 0; 
    50 }
    最大权闭合子图
  • 相关阅读:
    Delphi String的散漫记录,真是知识无数,陷阱无数(转)
    GB2312 编码
    Windows系统字体与文件对照表
    Windows字符集的统一与转换
    Delphi 的绘图功能[10]
    各种字符集和编码详解
    NTC热敏电阻参数
    Spring Cloud 学习笔记(一)——入门、特征、配置
    上坡路定点停车与坡道起步
    网闸结构和工作原理
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10255461.html
Copyright © 2011-2022 走看看