zoukankan      html  css  js  c++  java
  • 题解 P2805 【[NOI2009]植物大战僵尸】

    题目链接

    Solution [NOI2009] 植物大战僵尸

    题目大意:给定一个(n)(m)列的图,每个点可以保护一些点.每个点有一个权值(可以为负数).如果要选取一个点则必须选取保护它的点以及它右边的点.试求最大权值和(可以一个点也不选)

    最大权闭合子图


    分析:读懂题意之后这题基本上就是一个最大权闭合子图的模板题了吧.只不过要注意一个点:图可能有环

    您大可以放一个无CD的玉米加农炮对准一个坚果

    也就是说如果你遇到一些植物相互保护 (or) 左边的植物保护右边的植物这种情况的话你是无解的.按照我们的算法这个环是有贡献的,但很遗憾在实际问题中它没有意义

    所以我们可以用一次拓扑排序来找出所有的环,在拓扑排序过程中访问到的点才有实际意义

    注意题中下标从(0)开始

    然后就上代码了

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    using namespace std;
    const int maxn = 1024;
    const int maxm = (maxn * maxn) << 3;
    namespace Dinic{//Dinic板子
        const int INF = 0x7fffffff;
        struct Edge{
            int from,to,cap,flow;
            Edge() = default;
            Edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d){}
        }Edges[maxm];
        int head[maxn],nxt[maxm],tot = 1;
        inline void clear(){
            memset(head,0,sizeof(head));
            memset(nxt,0,sizeof(nxt));
            tot = 1;
        }
        inline void addedge(int from,int to,int cap){
            Edges[++tot] = Edge(from,to,cap,0);
            nxt[tot] = head[from];
            head[from] = tot;
            Edges[++tot] = Edge(to,from,0,0);
            nxt[tot] = head[to];
            head[to] = tot;
        }
        int d[maxn];
        inline bool bfs(int s,int t){
            queue<int> Q;
            memset(d,-1,sizeof(d));
            d[s] = 0;
            Q.push(s);
            while(!Q.empty()){
                int u = Q.front();Q.pop();
                for(int i = head[u];i;i = nxt[i]){
                    Edge &e = Edges[i];
                    if(e.cap > e.flow && d[e.to] == -1){
                        d[e.to] = d[u] + 1;
                        Q.push(e.to);
                    }
                }
            }
            return d[t] != -1;
        }
        int cur[maxn];
        inline int dfs(int u,int a,int t){
            if(u == t || a == 0)return a;
            int ret = 0,f;
            for(int &i = cur[u];i;i = nxt[i]){
                Edge &e = Edges[i];
                if(d[u] + 1 == d[e.to] && (f = dfs(e.to,min(a,e.cap - e.flow),t)) > 0){
                    ret += f;
                    Edges[i].flow += f;
                    Edges[i ^ 1].flow -= f;
                    a -= f;
                    if(a == 0)break;
                }
            }
            return ret;
        }
        inline int maxflow(int s,int t){
            int ret = 0;
            while(bfs(s,t)){
                memcpy(cur,head,sizeof(head));
                ret += dfs(s,INF,t);
            }
            return ret;
        }
    }
    vector<int> G[maxn];
    int n,m,siz,s,t,degree[maxn],mark[maxn],score[maxn],ans;
    inline void toposort(){//拓扑排序
    	queue<int> Q;
    	for(int i = 1;i <= siz;i++)if(!degree[i])Q.push(i);
    	while(!Q.empty()){
    		int u = Q.front();Q.pop();
    		mark[u] = 1;
    		for(int v : G[u])
    			if(!(--degree[v]))
    				Q.push(v);
    	}
    }
    inline int id(int x,int y){//根据坐标找编号
    	return (x - 1) * m + y;
    }
    int main(){
    #ifdef LOCAL
    	freopen("fafa.in","r",stdin);
    #endif
    	scanf("%d %d",&n,&m);
    	siz = n * m,s = siz + 1,t = s + 1;
    	for(int i = 1;i <= n;i++)
    		for(int k,x,y,j = 1;j <= m;j++){
    			scanf("%d %d",&score[id(i,j)],&k);
    			if(j != m)G[id(i,j + 1)].push_back(id(i,j)),degree[id(i,j)]++;//右边的点"保护"着左边的点
    			while(k--)
    				scanf("%d %d",&x,&y),G[id(i,j)].push_back(id(x + 1,y + 1)),degree[id(x + 1,y + 1)]++;
    		}
    	toposort();
    	for(int i = 1;i <= n;i++)
    		for(int j = 1;j <= m;j++)
    			if(mark[id(i,j)]){
    				if(score[id(i,j)] > 0)ans += score[id(i,j)],Dinic::addedge(s,id(i,j),score[id(i,j)]);
    				else Dinic::addedge(id(i,j),t,-score[id(i,j)]);
    				for(int v : G[id(i,j)])
    					if(mark[v])
    						Dinic::addedge(v,id(i,j),Dinic::INF);//如果要打它保护的植物,那么就必须打它
    			}
    	ans = ans - Dinic::maxflow(s,t);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    git-【六】分支的创建与合并
    git-【五】远程仓库
    git-【四】撤销修改和删除文件操作
    git-【三】理解工作区与暂存区的区别
    git-【二】本地git操作提交、版本回退
    git-【一】概述安装
    java-基础-【四】实际编程中的对象
    博客园打赏、赞助功能
    js-template-art【四】通过helper方法注册,调用外部方法
    js-template-art【三】js api
  • 原文地址:https://www.cnblogs.com/colazcy/p/11515019.html
Copyright © 2011-2022 走看看