BZOJ1565: [NOI2009]植物大战僵尸 最小割 拓扑排序

原创 2017年01月03日 18:15:42

题意:N*M草地,每个植物有权值,可正可负。每个植物被同一行右边植物保护,每个植物还能额外保护一些其他的植物。求吃掉一些植物的最大收益。
n<=20,m<=30。
显然是最大权闭合子图模型,用最小割解决。
由于图里有环,所以不能直接跑网络流。(如果一个环中一个点连源点,一个点连汇点,最小割只会割掉其中一条,但实际上,所有环上的点都不能选。)
但是tarjan缩点是不行的,因为如果一条路径上出现不能选的点,那么这个点之后的点也都不能选,这就不好维护了。
考虑什么样的点不应存在于网络流的建图中。首先,环上的点不能选;其次,如果一个点指向不能选的点,那么这个点也不能选。将边反向,变为不能选的点指向的点也不能选,所以能选的点就是拓扑排序能走到的点。
之后正常建图跑最大流就可以了。

#include<cstdio>
#include<queue>
#include<cstring>
#define gm 800
using namespace std;
const int s=0,t=601,inf=0x7fffffff;
struct e
{
    int t,flow;
    bool is_r;
    e *n,*r;
    e(int t,e *n,int flow,bool is_r=0):t(t),n(n),flow(flow),is_r(is_r){}
}*f[gm];
int rd[gm],w[gm];
inline void link(int x,int y,int flow)
{
    f[x]=new e(y,f[x],flow);
    f[y]=new e(x,f[y],0,true);
    f[x]->r=f[y],f[y]->r=f[x];
    ++rd[x];
}
bool ok[gm];
int n,m,ans=0;
inline void pre_choose()
{
    queue<int> q;
    for(int i=1;i<=n;++i) if(!rd[i]) q.push(i);
    while(!q.empty())
    {
        int now=q.front();q.pop();
        for(e *i=f[now];i;i=i->n)
        if(i->is_r)
        {
            --rd[i->t];
            if(!rd[i->t]) q.push(i->t);
        }
        ok[now]=1;
        if(w[now]>0) ans+=w[now],link(s,now,w[now]);
        else link(now,t,-w[now]);
    }
}
inline int min(int a,int b){return a<b?a:b;}
int d[gm];
inline bool bfs()
{
    queue<int> q;
    memset(d,-1,sizeof d);
    d[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int now=q.front();q.pop();
        if(now==t) return 1;
        for(e *i=f[now];i;i=i->n)
        if(ok[i->t]&&i->flow&&d[i->t]==-1)
        d[i->t]=d[now]+1,q.push(i->t);
    }
    return 0;
}
int send(int now=s,int flow=inf)
{
    if(now==t) return flow;
    int last=flow;
    for(e *i=f[now];i&&last;i=i->n)
    if(d[i->t]==d[now]+1)
    {
        int kre=send(i->t,min(last,i->flow));
        i->flow-=kre;
        i->r->flow+=kre;
        last-=kre;
    }
    if(last) d[now]=-1;
    return flow-last;
}
int main()
{
    scanf("%d%d",&n,&m);
    ok[t]=1;
    n*=m;
    for(int i=1,k;i<=n;++i)
    {
        scanf("%d%d",w+i,&k);
        if(i%m) link(i,i+1,inf);
        while(k--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            link(x*m+y+1,i,inf);
        }
    }
    pre_choose();
    while(bfs())
    ans-=send();
    printf("%d\n",ans);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

【bzoj1565】【NOI2009】【植物大战僵尸】【拓扑排序+最小割】

Description Input Output 仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。 Sample Input...
  • sunshinezff
  • sunshinezff
  • 2016年03月29日 11:19
  • 222

bzoj1565: [NOI2009]植物大战僵尸 最小割

若a保护b,则a向b连边 发现保护关系若形成环,则环以及环间接保护都不可攻击 删去这些点,然后就是最大权闭合子图模型 若v[x]x 权-v[x] 否则 x-T 权v[x] ...
  • EOD_realize
  • EOD_realize
  • 2015年01月04日 21:02
  • 778

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

最小割+拓扑排序
  • SenyeLicone
  • SenyeLicone
  • 2017年02月20日 12:29
  • 212

【NOI2009】bzoj1565 植物大战僵尸

最大权闭合子图+拓扑排序
  • sdfzyhx
  • sdfzyhx
  • 2017年01月23日 19:55
  • 130

bzoj1565【NOI2009】植物大战僵尸

最大权闭合子图+拓扑排序
  • AaronGZK
  • AaronGZK
  • 2016年07月03日 14:54
  • 2072

bzoj1565 [NOI2009]植物大战僵尸

(http://www.elijahqi.win/2018/01/03/bzoj1565-noi2009%E6%A4%8D%E7%89%A9%E5%A4%A7%E6%88%98%E5%83%B5%E5...
  • elijahqi
  • elijahqi
  • 2018年01月03日 19:25
  • 13

【bzoj1565】[NOI2009]植物大战僵尸

1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2164  Solved: 1001[Submit][Sta...
  • chty2018
  • chty2018
  • 2016年11月21日 13:04
  • 96

【BZOJ1565】【NOI2009】植物大战僵尸

【题目链接】 点击打开链接 【思路要点】 题目中的限制可以总结为“若选取A,则必须选取B”,考虑最大权闭合子图问题。但是我们从样例中发现原图是可能存在环的,而...
  • qq_39972971
  • qq_39972971
  • 2018年01月15日 09:01
  • 23

使用Cocos2d-lua开发植物大战僵尸06-僵尸类的实现

僵尸也是分类的,比如什么普通僵尸啊,铁桶僵尸啊之类的,所以我们要写一个僵尸的基类,叫做ZombiesBase,僵尸基类包含了僵尸都共同拥有的一些属性,僵尸的属性也比较多,有类型zombiesType,...
  • sinat_16095273
  • sinat_16095273
  • 2015年11月09日 16:59
  • 511

Android植物大战僵尸附源码

本文介绍cocos2d-android实现的Android植物大战僵尸,最后附源码   =======================================================...
  • codehxy
  • codehxy
  • 2014年05月11日 12:03
  • 3961
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:BZOJ1565: [NOI2009]植物大战僵尸 最小割 拓扑排序
举报原因:
原因补充:

(最多只允许输入30个字)