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);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

BZOJ 1565 NOI 2009 植物大战僵尸 最小割 拓扑排序

#include #include #include #define FOR(i,j,k) for(i=j;i<=k;++i) using namespace std; const int in...

Bzoj1565:[NOI2009]植物大战僵尸:拓扑排序+网络流

题目链接:1565:[NOI2009]植物大战僵尸 显然的最大权闭合图模型,但是裸上是错的 每个植物相他所攻击的位置连边,如果形成一个环那么这个换必然无解 进一步,这个环所保护的点都不能取到 ...

BZOJ1565——[NOI2009]植物大战僵尸

1、题意:有一些点,点与点之间有保护关系,每个点都有一个权值,求能获得的最大值 2、分析:裸的最大权闭合图,用网络流进行求解,然后我们发现点与点之间的保护关系可能构成环,这样网络流是无法处理的,然后...

[题解]bzoj1565(NOI2009)植物大战僵尸

此文中有部分内容转自http://www.cnblogs.com/jianglangcaijin/p/3799831.html Description Input Output 仅包含一个整...

BZOJ 1565: [NOI2009]植物大战僵尸

拓扑+最小割 想画图解释的。。。可是画图不太好用啊 不如一起来膜神犇吧! #include #include #include #include #include #define wz(x,y) ...

bzoj1565【NOI2009】植物大战僵尸

最大权闭合子图+拓扑排序

BZOJ 1565 NOI 2009 Day2 T1 植物大战僵尸

题目大意:小明同学在玩植物大战僵尸游戏,现在轮到他控制僵尸打败植物。植物分布在一个m*n的矩形中。僵尸从右边向左边攻击,要想打到左边的植物,要先打到它右边的植物。有一些植物是可以保护其他植物的,僵尸不...

【NOI2009】bzoj1565 植物大战僵尸

最大权闭合子图+拓扑排序

bzoj 1565: [NOI2009]植物大战僵尸

Description Input Output 仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。 Sample Input...

[NOI2009]植物大战僵尸

这道题跟NOI2006 最大获利其实是很像的 一样都是要搞定一些点才能搞定另一些点,然后有些点正权有些点负权 这种问题,其实是最大权闭合子图 amber的最小割论文有详细的讲解法和证明 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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