bzoj 1565植物大战僵尸

31 篇文章 0 订阅
16 篇文章 0 订阅

题意:很麻烦,就不说了

思路:有向闭合图:闭合图中任意点的后继还在闭合图中。

           物理意义:一个事件发生,他所有的前提都需要发生

           在任意有向带权图中,只要有依赖关系需要解决,最大权闭合子图都普遍成立。

          拓扑排序中没有遍历到的点就是不可达点,不可达点不能在网络流中出现。为啥呢,我试了一下,把这些点放入网络流中             跑就WA了,我也不知道为啥,以后再来填坑吧。难道只有可达点才可以与原点相连吗,听起来有点道理。

          最大权 = 所有正权点的和 - maxflow

坑点:最开始建图建丑了,T掉了。其实只要把每个点和他之前一个点建边就行,不用把他前面的所有点都连边。

收获:拓扑排序访问不到的点不只是环中的点,还有环可达的所有点。物理意义就是永远也不可能发生的事件。以后我再也不用            紫书上的拓扑排序板子了,就用广搜写了。

#include <bits/stdc++.h>
using namespace std;
typedef int LL;
const LL maxn = 1000;
const LL maxm = 1000000;
const LL inf = 0x3f3f3f3f;
LL v[maxn],M,N,in[maxn],he[maxn],ver[maxm],ne[maxm],vis[maxn],tot;
struct dinic{
    LL he[maxn],ne[maxm],ver[maxm],edge[maxm],d[maxn];
    LL s,t,tot;
    queue<LL> que;
    void init( LL n ){
        for( LL i = 0;i <= n;i++ ){
            he[i] = 0;
        }
        tot = 1;
    }
    void add( LL x,LL y,LL z ){
        ver[++tot] = y; ne[ tot ] = he[x]; he[x] = tot; edge[ tot ] = z;
        ver[++tot] = x; ne[tot] = he[y]; he[y] = tot;edge[tot] = 0;
    }
    bool bfs(){
        memset( d,0,sizeof( d ) );
        while( que.size() ) que.pop();
        que.push( s );
        d[s] = 1;
        while( que.size() ){
            LL x = que.front();
            que.pop();
            for( LL cure = he[x];cure;cure = ne[cure] ){
                LL y = ver[cure];
                if( edge[cure] && !d[y] ){
                    que.push( y );
                    d[ y ] = d[x] + 1;
                    if( y == t ) return 1;
                }
            }
        }
        return 0;
    }
    LL dfs( LL x,LL flow ){
        if( x== t ) return flow;
        LL rest = flow,k;
        for( LL cure = he[x];cure && rest;cure = ne[cure] ){
            LL y = ver[cure];
            if( edge[cure] && d[ y ] == d[x] + 1 ){
                k = dfs( y,min( rest,edge[cure] ) );
                if( !k ) d[ y ] = 0;
                edge[cure] -= k;
                edge[ cure^(LL)1 ] += k;
                rest -= k;
            }
        }
        return flow - rest;
    }
    LL max_flow( LL x,LL y ){
        s = x; t = y;
        LL maxflow = 0;
        LL flow = 0;
        while( bfs() )
            while( flow = dfs( s,inf ) ) maxflow += flow;
        return maxflow;
    }
    
}  g;
LL get_id( LL r,LL c ){
    return r*M + c + 1;
}
void init( int n ){
    for( LL i = 0;i <= n;i++ ) he[i] = in[i] =  vis[i] = 0;
    tot = 1;
}
void add( LL x,LL y ){
    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;
}
queue<LL> que;
void topsort(){
    LL n = get_id( N-1,M-1 );
    for( LL i = 1;i <= n;i++ ){
        if( !in[i] ){
            que.push( i );
            vis[i] = 1;
        }
    }
    while( que.size() ){
        LL x = que.front();
        que.pop();
        for( LL cure = he[x];cure;cure = ne[cure] ){
            LL y  = ver[cure];
            in[y]--;
            if( !in[y] ){
                 vis[y] = 1;
                que.push( y );
            }
        }
    }

}
int main()
{
    LL score,w,r,c;
    scanf("%d%d",&N,&M);
    LL n = get_id( N-1,M-1 );
    init( n );
    for( LL i = 0;i < N;i++ ){
        for( LL j = 0;j < M;j++ ){
            scanf("%d",&score);
            LL id = get_id( i,j );
            if( id % M != 1 ){
                add( id,id-1 );
                in[id-1]++;
            }
            v[id] = score;
            scanf("%d",&w);
            for( LL i = 1;i<= w;i++ ){
                scanf("%d%d",&r,&c);
                LL id2 = get_id( r,c );
                    add( id,id2 );
                    in[id2]++;
            }
        }
    }
    topsort();
    LL SS = 0,TT = n+1;
    g.init( TT );
    for( LL x = 1;x <= n;x++  ){
        if( !vis[x] ) continue;
        if( v[x] >= 0 ){
            g.add( SS,x,v[x] );
        }else{
            g.add( x,TT,-v[x] );
        }
        for( LL cure = he[x];cure;cure = ne[cure] ){
            LL y = ver[cure];
            if( !vis[y] ) continue;
            g.add( y,x,inf );
        }
    }
    LL maxflow = g.max_flow( SS,TT );
    //LL ans = g.solve();
    LL sum = 0;
    for( LL i = 1;i <= n;i++ ){
        if( vis[i] && v[i] > 0 ) sum += v[i];
    }
    printf("%d",sum - maxflow);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值