BZOJ1565 植物大战僵尸

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1565

 

这题看上去并不会做,结果又是最大权闭合子图的裸题。

于是就去看了一发论文,明白建图的技巧。

论文地址:最小割模型在信息学竞赛中的应用》

嗯,讲这个的部分在第三章。

好了,看完论文就知道DAG的怎么搞了。

这题可能有环,因为环上的不能选,有边连到环上[被环上的点保护着的]的也不能选。

那么我们就把环弄掉,连在环上的呢?用反图,然后拓扑排序就可以同时把这两种点排除掉了。

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=32;
const int maxt=610;
const int INF=0x3f3f3f3f;

struct Node{
    int data,next,low;
}node[maxt*maxt*2];

#define now node[point].data
#define then node[point].next
#define www node[point].low

struct Edge{
    int u,v;
}edge[maxt*maxt];

int n,m,tot,cnt;
int s,t,Idex,ans;
int indeg[maxt],stack[maxt],top;
int head[maxt],cur[maxt];
int dis[maxt],que[maxt];
int val[maxn][maxn],ind[maxn][maxn];
bool used[maxt];

void add1(int u,int v){
    node[cnt].data=v;node[cnt].next=head[u];head[u]=cnt++;indeg[v]++;
    edge[cnt].u=v,edge[cnt].v=u;
}

void add(int u,int v,int w){
    node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++;
    node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=0;head[v]=cnt++;
}

bool BFS(){
    memset(dis,-1,sizeof(dis));
    int H=0,T=1;dis[0]=0;
    while(H<T){
        H++;
        for(int point=head[que[H]];point!=-1;point=then)
            if(www && dis[now]<0){
                dis[now]=dis[que[H]]+1;
                que[++T]=now;
            }
    }
    return dis[t]>0;
}

int dfs(int x,int low){
    if(x==t) return low;
    int Low;
    for(int &point=cur[x];point!=-1;point=then)
        if(www && dis[now]==dis[x]+1){
            Low=dfs(now,min(low,www));
            if(Low){
                www-=Low;node[point^1].low+=Low;
                return Low;
            }
        }
    return 0;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("1565.in","r",stdin);
    freopen("1565.out","w",stdout);
#endif
    int x,y,k;

    scanf("%d%d",&n,&m);
    t=n*m+1;
    for(int i=1;i<t;i++) head[i]=-1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        ind[i][j]=++Idex;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d%d",&val[i][j],&k);
            while(k--){
                scanf("%d%d",&x,&y);
                x++,y++;
                add1(ind[i][j],ind[x][y]);
            }
            if(j!=1)
                add1(ind[i][j],ind[i][j-1]);
        }
    for(int i=1;i<t;i++)
        if(!indeg[i]) stack[++top]=i;
    while(top){
        k=stack[top--],used[k]=true;
        for(int point=head[k];point!=-1;point=then)
            if(--indeg[now]==0)
                stack[++top]=now;
    }
    
    tot=cnt;cnt=0;
    for(int i=s;i<=t;i++) head[i]=-1;
    for(int i=1;i<=tot;i++)
        if(used[edge[i].u] && used[edge[i].v])
            add(edge[i].u,edge[i].v,INF);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(used[ind[i][j]]){
                if(val[i][j]>0)
                    add(s,ind[i][j],val[i][j]),ans+=val[i][j];
                else if(val[i][j]<0)
                    add(ind[i][j],t,-val[i][j]);
            }
    int flag;
    while(BFS()){
        memcpy(cur,head,sizeof(cur));
        while(flag=dfs(s,INF))
            ans-=flag;
    }
    
    printf("%d",ans);
    return 0;
}
View Code

 

posted @ 2016-02-27 10:24  诚叙  阅读(283)  评论(0编辑  收藏  举报