[NOI2009]植物大战僵尸

关系复杂,数据小,网络流

依赖关系,最大权闭合子图

每个点还会无形地保护后面的植物

先tarjan找SCC,然后sz>1点不能攻击。再每个不能攻击的点dfs,其保卫的点也不能攻击

不能攻击的点选择上,就必须选择-inf的点。

最大权闭合子图跑即可

SCC的时候,每个点还要和后面的点连边。

代码:

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mp make_pair
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=606;
const int inf=0x3f3f3f3f;
struct node{
    int w;
    int nxt,to;
}e[2*(N+N*N+N+2333)];
int hd[N],cnt;
int n,m,s,t;
vector<pair<int,int> >mem[N];
void add(int x,int y,int z,int typ){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    e[cnt].w=z;
    hd[x]=cnt;
    
    if(typ){
        e[++cnt].nxt=hd[y];
        e[cnt].to=x;
        e[cnt].w=0;
        hd[y]=cnt;
    }
}
int dfn[N];
int co[N];
int sz[N];
int tot,df;
int low[N];
int sta[N],top;
int in[N];
bool vis[N];
void tarjan(int x){
//    cout<<" tarjan x "<<x<<endl;
    dfn[x]=low[x]=++df;
    in[x]=1;
    sta[++top]=x;
    for(reg i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(in[y]) low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x]){
        ++tot;
        int z;
        do{
            z=sta[top];
            co[z]=tot;
            ++sz[tot];
            in[z]=0;
            --top;
        }while(z!=x);
    }
}
int d[N];
bool no[N];
int val[N];
int dfs(int x,int flow){
    int res=flow;
//    cout<<" dfs "<<x<<" "<<flow<<endl;
    if(x==t) return flow;
    for(reg i=hd[x];i&&res;i=e[i].nxt){
        int y=e[i].to;
        if(e[i].w&&d[y]==d[x]+1){
            int k=dfs(y,min(res,e[i].w));
            if(!k) d[y]=0;
            res-=k;
            e[i].w-=k;
            e[i^1].w+=k;
        }
    }
    return flow-res;
}
int q[N],l,r;
bool bfs(){
    memset(d,0,sizeof d);
    l=1,r=0;
    q[++r]=s;
    d[s]=1;
    while(l<=r){
        int x=q[l++];
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(e[i].w){
                if(!d[y]){
                    d[y]=d[x]+1;
                    q[++r]=y;
                    if(y==t) return true;
                }
            }
        }
    }
    return false;
}int num(int x,int y){
    return (x-1)*m+y;
}
void dele(int x,int y){
//    cout<<" dele x y "<<x<<" "<<y<<endl;
    if(vis[num(x,y)]) return;
    no[num(x,y)]=1;
    vis[num(x,y)]=1;
    if(y>1) dele(x,y-1);
    for(reg i=0;i<(int)mem[num(x,y)].size();++i){
        if(!vis[num(mem[num(x,y)][i].fi,mem[num(x,y)][i].se)]){
            dele(mem[num(x,y)][i].fi,mem[num(x,y)][i].se);
        }
    }
}

int main(){    
    rd(n);rd(m);
    int x,y;
    for(reg i=1;i<=n;++i){
        for(reg j=1;j<=m;++j){
            int id=num(i,j);
            rd(val[id]);
            int w;
            rd(w);
            for(reg k=1;k<=w;++k){
                rd(x);rd(y);
                ++x;++y;
                add(id,num(x,y),0,0);
                mem[id].push_back(mp(x,y));
            }
            if(j!=1){
                add(id,num(i,j-1),0,0);
            }
        }
    }
    for(reg i=1;i<=n*m;++i){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    for(reg i=1;i<=n*m;++i){
        if(sz[co[i]]>1){
            no[i]=1;
        }
    }
    
    for(reg i=1;i<=n;++i){
        for(reg j=1;j<=m;++j){
            if(!vis[num(i,j)]&&no[num(i,j)]){
                dele(i,j);
            }
        }
    }
    s=0;
    t=n*m+2;
    val[n*m+1]=-inf;
    memset(hd,0,sizeof hd);
    cnt=1;
    int ans=0;
    
//    for(reg i=1;i<=n;++i){
//        for(reg j=1;j<=m;++j){
//            cout<<no[num(i,j)]<<" ";
//        }cout<<endl;
//    }
//    
    for(reg i=1;i<=n;++i){
        for(reg j=1;j<=m;++j){
            if(j!=m) {
                add(num(i,j),num(i,j+1),inf,1);
            }
            for(reg k=0;k<(int)mem[num(i,j)].size();++k){
                add(num(mem[num(i,j)][k].fi,mem[num(i,j)][k].se),num(i,j),inf,1);
            }
            if(no[num(i,j)]){
                add(num(i,j),n*m+1,inf,1);
            }
            if(val[num(i,j)]>0){
                ans+=val[num(i,j)];
                add(s,num(i,j),val[num(i,j)],1);
            }else{
                add(num(i,j),t,-val[num(i,j)],1);
            }
        }
    }
    add(n*m+1,t,inf,1);
//    cout<<" after no 3 "<<endl;
    int flow=0;
    while(bfs()){
        while(flow=dfs(s,inf)) ans-=flow;
    }
    cout<<ans;
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/1/16 16:45:42
*/
原文地址:https://www.cnblogs.com/Miracevin/p/10280318.html