zoukankan      html  css  js  c++  java
  • [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 。


    想法##

    僵尸攻击(P_{r,c})的植物的前提是已攻击所有可以保护这个植物的植物
    明显是一个“最大权闭合图”问题,最小割解决。

    需要特别判断的是这个图中不能有环,因为环中的植物互相保护,都不能被攻击。
    除环外,所有可走到环的点也不能有,因为有了这些点闭合图中就必须有环。
    所有要先dfs一遍把这些点都标出来。
    跑dinic时注意不能走到这些点上。


    代码##

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
     
    #define INF 200000000
     
    using namespace std;
     
    const int N = 605;
    const int M = 605*605+605;
     
    int read(){
        char ch=getchar();
        int x=0,f=1;
        while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return f*x;    
    }
     
    struct node{
        int v,f;
        node *next,*rev;       
    }pool[M<<1],*h[N];
    int cnt;
     
    void addedge(int u,int v,int f){
        node *p=&pool[++cnt],*q=&pool[++cnt];
        p->v=v;p->next=h[u];h[u]=p; p->f=f;p->rev=q;
        q->v=u;q->next=h[v];h[v]=q; q->f=0;q->rev=p;     
    }
     
    int n,m;
    int C[25][35];
     
    int vis[N],cir[N];
    void findcir(int u){
        int v;
        vis[u]=1;
        for(node *p=h[u];p;p=p->next)
            if(p->f){
                if(!vis[v=p->v]) {
                    findcir(v);
                    if(cir[v]) cir[u]=1;
                }
                else if(vis[v]==1) cir[u]=1;
                else if(cir[v]) cir[u]=1;
            }
        vis[u]=2;
    }
     
    int S,T;
    int level[N],que[N];
    bool bfs(){
        int head=0,tail=0,u,v;
        for(int i=S;i<=T;i++) level[i]=-1;
        level[S]=1; que[tail++]=S;
        while(head<tail){
            int u=que[head++];
            for(node *p=h[u];p;p=p->next)
                if(p->f && level[v=p->v]==-1 && !cir[v]){
                    level[v]=level[u]+1;
                    que[tail++]=v;        
                }
            if(level[T]!=-1) return true;
        }     
        return false;
    }
    int find(int u,int f){
        int s=0,t,v;
        if(u==T) return f;
        for(node *p=h[u];p;p=p->next)
            if(p->f && s<f && level[v=p->v]==level[u]+1 && !cir[v]){
                t=find(v,min(p->f,f-s));
                if(t){
                    s+=t;
                    p->f-=t;
                    p->rev->f+=t;      
                }
            }
        if(!s) level[u]=-1;
        return s;
    }
    int dinic(){
        int f=0;
        while(bfs()) f+=find(S,INF);
        return f;    
    }
     
    int main()
    {
        int u,v,w;
        n=read();m=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                int t=(i-1)*m;
                C[i][j]=read();w=read();
                for(int k=0;k<w;k++){
                    u=read();v=read();
                    addedge(u*m+v+1,t+j,INF);   
                }
            }
        for(int i=1;i<=n;i++){
            int t=(i-1)*m;
            for(int j=m-1;j>0;j--)
                addedge(t+j,t+j+1,INF);
        }
         
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(vis[(i-1)*m+j]!=2)
                    findcir((i-1)*m+j);
         
        S=0; T=n*m+1;
        int sum=0;
        for(int i=1;i<=n;i++){
            int t=(i-1)*m;
            for(int j=1;j<=m;j++){
                if(cir[t+j]) continue;
                if(C[i][j]>0) {
                    addedge(S,t+j,C[i][j]);
                    sum+=C[i][j];              
                }
                else if(C[i][j]<0)
                    addedge(t+j,T,-C[i][j]);
            }
        }
        sum-=dinic();
        printf("%d
    ",sum);
         
        return 0;    
    }
    
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    【转】Android——设置颜色的三种方法
    Eclipse Android安装APP时覆盖安装问题
    自定义数组,实现输出改数组的长度、最大值和最小值
    用程序实现对数组a[45,96,78,6,18,66,50]中的元素进行排序
    PHP面试题2
    PHP面试题
    gulp
    移动端base.css
    笔记
    mouseover和mouseout事件在鼠标经过子元素时也会触发
  • 原文地址:https://www.cnblogs.com/lindalee/p/8414383.html
Copyright © 2011-2022 走看看