BZOJ1565: [NOI2009]植物大战僵尸

Description

Input

Output

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

Sample Input

3 2
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0

Sample Output

25

HINT

在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。 
一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。 
【大致数据规模】
约20%的数据满足1 ≤ N, M ≤ 5;
约40%的数据满足1 ≤ N, M ≤ 10;
约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。

经典的最大权闭合子图,我们把依赖关系成环的节点以及依赖一个环的节点删掉,然后就是模板题。
然后我写了个Tarjan。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
    if(head==tail) {
        int l=fread(buffer,1,BufferSize,stdin);
        tail=(head=buffer)+l;
    }
    return *head++;
}
inline int read() {
    int x=0,f=1;char c=Getchar();
    for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=610;
const int maxm=1000010;
const int inf=1e9;
struct ISAP{
    struct tedge{int x,y,w,next;}adj[maxm];int ms,fch[maxn];
    int d[maxn],s[maxn],cur[maxn],gap[maxn],n,top;
    void init(int n){
        this->n=n;ms=0;top=0;
        memset(d,-1,sizeof(d));
        memset(fch,-1,sizeof(fch));
        return;
    }
    void AddEdge(int u,int v,int w){
        adj[ms]=(tedge){u,v,w,fch[u]};fch[u]=ms++;
        adj[ms]=(tedge){v,u,0,fch[v]};fch[v]=ms++;
        return;
    }
    void bfs(){
        queue<int>Q;Q.push(n);d[n]=0;
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            for(int i=fch[u];i!=-1;i=adj[i].next){
                int v=adj[i].y;
                if(d[v]==-1) d[v]=d[u]+1,Q.push(v);
            }
        } return;
    }
    int solve(int S,int T){
        n=T;bfs();int k=S,i,flow=0;
        for(i=0;i<=n;i++) cur[i]=fch[i],gap[d[i]]++;
        while(d[S]<n){
            if(k==n){
                int mi=inf,pos;
                for(i=0;i<top;i++) if(adj[s[i]].w<mi) mi=adj[s[i]].w,pos=i;
                for(i=0;i<top;i++) adj[s[i]].w-=mi,adj[s[i]^1].w+=mi;
                flow+=mi;top=pos;k=adj[s[top]].x;
            }
            for(i=cur[k];i!=-1;i=adj[i].next){
                int v=adj[i].y;
                if(adj[i].w&&d[k]==d[v]+1){cur[k]=i;k=v;s[top++]=i;break;}
            }
            if(i==-1){
                int lim=n;
                for(i=fch[k];i!=-1;i=adj[i].next){
                    int v=adj[i].y;
                    if(adj[i].w&&d[v]<lim) lim=d[v],cur[k]=i;
                } if(--gap[d[k]]==0) break;
                d[k]=lim+1;gap[d[k]]++;
                if(k!=S) k=adj[s[--top]].x;
            }
        } return flow;
    }
}sol;
int n,m,val[maxn];
int id(int x,int y) {return (x-1)*m+y;}
int from[maxm],to[maxm],first[maxn],next[maxm],e;
void AddEdge(int u,int v) {
    from[++e]=u;to[e]=v;next[e]=first[u];first[u]=e;
}
int S[maxn],scn[maxn],cnt[maxn],top,num,pre[maxn],low[maxn],mark[maxn],dfs_clock;
void dfs(int x) {
    low[x]=pre[x]=++dfs_clock;S[++top]=x;
    for(int i=first[x];i;i=next[i]) {
        if(!pre[to[i]]) dfs(to[i]),low[x]=min(low[x],low[to[i]]);
        else if(!scn[to[i]]) low[x]=min(low[x],pre[to[i]]);
    }
    if(low[x]==pre[x]) {
        num++;for(;;) {
            int u=S[top--];
            scn[u]=num;cnt[num]++;
            if(u==x) break;
        }
    }
}
int main() {
    n=read();m=read();
    rep(i,1,n) rep(j,1,m) {
        val[id(i,j)]=read();
        int k=read(),u=id(i,j);
        while(k--) {
            int x=read()+1,y=read()+1;
            AddEdge(id(x,y),u);
        }
        if(j!=m) AddEdge(id(i,j),id(i,j+1));
    }
    rep(i,1,n*m) if(!pre[i]) dfs(i);
    rep(i,1,n*m) if(cnt[scn[i]]>1) mark[i]=1;
    int S=n*m+1,T=n*m+2,sum=0;sol.init(T);
    rep(i,1,e) if(mark[to[i]]) sol.AddEdge(from[i],T,1e9);
    else sol.AddEdge(from[i],to[i],1e9);
    rep(i,1,n*m) if(!mark[i]) {
        if(val[i]>0) sum+=val[i],sol.AddEdge(S,i,val[i]);
        else sol.AddEdge(i,T,-val[i]);
    }
    printf("%d\n",sum-sol.solve(S,T));
    return 0;
}
View Code

 

posted @ 2016-03-21 19:54  wzj_is_a_juruo  阅读(200)  评论(0编辑  收藏  举报