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 。

    经典的最大权闭合子图,我们把依赖关系成环的节点以及依赖一个环的节点删掉,然后就是模板题。
    然后我写了个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
    ",sum-sol.solve(S,T));
        return 0;
    }
    View Code
  • 相关阅读:
    ANSYS Workbench 16.0超级学习手册(附光盘)
    自控力(套装共2册)
    超实用记忆力训练法
    大愿法师“幸福人生”系列丛书——禅心商道
    高情商沟通术(写给所有深受社交困扰的人)
    青年职业形象管理手册(高等职业教育在线开放课程新形态一体化规划教材)
    1019. 括号匹配
    1026. 高精度除法
    1018. A+B Problem Revisited
    1015. 高精度乘法
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5303392.html
Copyright © 2011-2022 走看看