zoukankan      html  css  js  c++  java
  • [BZOJ1565][NOI2009]植物大战僵尸

    [BZOJ1565][NOI2009]植物大战僵尸

    试题描述

    输入

    输出

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

    输入示例

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

    输出示例

    25

    数据规模及约定

    约20%的数据满足1 ≤ N, M ≤ 5;
    约40%的数据满足1 ≤ N, M ≤ 10;
    约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。

    题解

    首先,把每一行右边的植物视为保护左边的植物。

    其次,保护关系成环的(包括这个环中的植物保护的所有植物,就是从这个环向外连出的所有点),显然不用考虑,直接删掉。

    然后,不妨先假设我们干掉所有 Score 为正的植物,不干所有 Score 为负的植物,考虑如何调整。

    于是,发现可以用最小割,令节点 u 属于 S(源点所在集合)时表示干掉 u 节点,属于 T(汇点所在集合)时表示不干 u 节点。

    第一步建图,对于 Score 为正的植物,从 s 向它连容量为 Score 的边;对于 Score 为负的植物,从它向 t 连容量为 -Score 的边。

    第二步建图,若 u 保护 v,从 v 向 u 连容量为正无穷的边,表示如果想干 v 你必须先干掉 u。

    最后,跑最小割(最大流),答案为删掉不用考虑的节点后所有 Score 的和 - 最小割。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxN 25
    #define maxM 35
    #define maxn 610
    #define maxm 721210
    #define oo 2147483647
    
    struct Edge {
    	int from, to, flow;
    	Edge() {}
    	Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
    };
    struct Dinic {
    	int s, t, n, m, head[maxn], next[maxm];
    	Edge es[maxm];
    	int hd, tl, Q[maxn], vis[maxn];
    	int cur[maxn];
    	void init(int _) {
    		n = _; m = 0;
    		memset(head, -1, sizeof(head));
    		return ;
    	}
    	void AddEdge(int a, int b, int c) {
    		es[m] = Edge(a, b, c); next[m] = head[a]; head[a] = m++;
    		es[m] = Edge(b, a, 0); next[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	bool BFS() {
    		memset(vis, 0, sizeof(vis)); vis[s] = 1;
    		hd = tl = 0; Q[++tl] = s;
    		while(hd < tl) {
    			int u = Q[++hd];
    			for(int i = head[u]; i != -1; i = next[i]) {
    				Edge& e = es[i];
    				if(e.flow && !vis[e.to]) {
    					vis[e.to] = vis[u] + 1;
    					Q[++tl] = e.to;
    				}
    			}
    		}
    		return vis[t] > 1;
    	}
    	int DFS(int u, int a) {
    		if(u == t || !a) return a;
    		int flow = 0, f;
    		for(int& i = cur[u]; i != -1; i = next[i]) {
    			Edge& e = es[i];
    			if(vis[e.to] == vis[u] + 1 && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	int MaxFlow(int s, int t) {
    		this->s = s; this->t = t;
    		int flow = 0;
    		while(BFS()) {
    			for(int i = 1; i <= n; i++) cur[i] = head[i];
    			flow += DFS(s, oo);
    		}
    		return flow;
    	}
    } sol;
    
    int M, val[maxn], head[maxn], next[maxm], to[maxm], ind[maxn], S[maxn], top;
    bool can[maxn], Gra[maxn][maxn];
    int cal(int x, int y, int m) {
    	return (x - 1) * m + y;
    }
    void AddEdge(int a, int b) {
    	to[++M] = b; next[M] = head[a]; head[a] = M; ind[b]++;
    	return ;
    }
    
    int main() {
    	int n = read(), m = read();
    	
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= m; j++) {
    			int u = cal(i, j, m);
    			val[u] = read();
    			int c = read();
    			while(c--) {
    				int x = read() + 1, y = read() + 1, v = cal(x, y, m);
    				AddEdge(u, v); Gra[u][v] = 1;
    			}
    		}
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j < m; j++) {
    			int u = cal(i, j, m), v = cal(i, j + 1, m);
    			if(!Gra[v][u]) AddEdge(v, u), Gra[v][u] = 1;
    		}
    	for(int i = 1; i <= n * m; i++) if(!ind[i]) S[++top] = i;
    	while(top) {
    		int u = S[top--];
    		can[u] = 1;
    //		printf("u: %d
    ", u);
    		for(int e = head[u]; e; e = next[e]) {
    			ind[to[e]]--;
    			if(!ind[to[e]]) S[++top] = to[e];
    		}
    	}
    	
    	sol.init(n * m + 2);
    	int s = n * m + 1, t = s + 1, ans = 0;
    //	for(int i = 1; i <= n * m; i++) printf("%d%c", val[i], i < n * m ? ' ' : '
    ');
    	for(int i = 1; i <= n * m; i++) if(can[i]) {
    		for(int e = head[i]; e; e = next[e]) if(can[to[e]])
    			sol.AddEdge(to[e], i, oo);
    		if(val[i] > 0) sol.AddEdge(s, i, val[i]), ans += val[i];
    		if(val[i] < 0) sol.AddEdge(i, t, -val[i]);
    	}
    	printf("%d
    ", ans - sol.MaxFlow(s, t));
    	
    	return 0;
    }
    
  • 相关阅读:
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    flowable 获取当前任务流程图片的输入流
    最新 接口api插件 Swagger3 更新配置详解
    springboot 集成 activiti 流程引擎
    java 在线考试系统源码 springboot 在线教育 视频直播功能 支持手机端
    阿里 Nacos 注册中心 配置启动说明
    springboot 集成外部tomcat war包部署方式
    java 监听 redis 过期事件
    springcloudalibaba 组件版本关系
    java WebSocket 即时通讯配置使用说明
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6402885.html
Copyright © 2011-2022 走看看