zoukankan      html  css  js  c++  java
  • [luoguP2805] [NOI2009]植物大战僵尸(网络流)

    传送门

    结论:这是最大权闭合图的模型

    因为可能A保护B,B保护A,出现环。

    所以由植物A向植物A保护的植物连边,然后拓扑排序,将环去掉。

    然后将拓扑排序的边反向连,建立最大权闭合图的模型。

    跑最大流(最小割),用正权边之和-最小割即为答案

    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #define N 1000001
    #define id(i, j) ((i - 1) * m + j)
    
    using namespace std;
    
    int n, m, s, t, T, cnt, sum;
    int head[N], to[N], nex[N], val[N], a[N], dis[N], cur[N], d[N];
    vector <int> vec[N];
    queue <int> q;
    
    inline int read()
    {
    	int x = 0, f = 1;
    	char ch = getchar();
    	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    	return x * f;
    }
    
    inline void add(int x, int y, int z)
    {
    	to[cnt] = y;
    	val[cnt] = z;
    	nex[cnt] = head[x];
    	head[x] = cnt++;
    }
    
    inline bool bfs()
    {
    	int i, u, v;
    	memset(dis, -1, sizeof(dis));
    	while(!q.empty()) q.pop();
    	q.push(s);
    	dis[s] = 0;
    	while(!q.empty())
    	{
    		u = q.front();
    		q.pop();
    		for(i = head[u]; ~i; i = nex[i])
    		{
    			v = to[i];
    			if(val[i] && dis[v] == -1)
    			{
    				dis[v] = dis[u] + 1;
    				if(v == t) return 1;
    				q.push(v);
    			}
    		}
    	}
    	return 0;
    }
    
    inline int dfs(int u, int maxflow)
    {
    	if(u == t) return maxflow;
    	int v, f, used = 0;
    	for(int &i = cur[u]; ~i; i = nex[i])
    	{
    		v = to[i];
    		if(val[i] && dis[v] == dis[u] + 1)
    		{
    			f = dfs(v, min(val[i], maxflow - used));
    			used += f;
    			val[i] -= f;
    			val[i ^ 1] += f;
    			if(used == maxflow) return maxflow;
    		}
    	}
    	return used;
    }
    
    inline int dinic()
    {
    	int i, ret = 0;
    	while(bfs())
    	{
    		for(i = s; i <= t; i++) cur[i] = head[i];
    		ret += dfs(s, 1e9);
    	}
    	return ret;
    }
    
    int main()
    {
    	int i, j, u, v, x, y;
    	n = read();
    	m = read();
    	s = 0, t = n * m + 1;
    	memset(head, -1, sizeof(head));
    	for(i = 1; i <= n; i++)
    		for(j = 1; j <= m; j++)
    		{
    			a[id(i, j)] = read();
    			if(j > 1)
    			{
    				d[id(i, j - 1)]++;
    				vec[id(i, j)].push_back(id(i, j - 1));
    			}
    			T = read();
    			while(T--)
    			{
    				x = read() + 1;
    				y = read() + 1;
    				d[id(x, y)]++;
    				vec[id(i, j)].push_back(id(x, y));
    			}
    		}
    	for(i = 1; i <= n * m; i++)
    		if(!d[i]) q.push(i);
    	while(!q.empty())
    	{
    		u = q.front();
    		q.pop();
    		for(i = 0; i < vec[u].size(); i++)
    			if(!(--d[vec[u][i]])) q.push(vec[u][i]);
    	}
    	for(u = 1; u <= n * m; u++)
    		if(!d[u])
    		{
    			if(a[u] > 0) add(s, u, a[u]), add(u, s, 0), sum += a[u];
    			if(a[u] < 0) add(u, t, -a[u]), add(t, u, 0);
    			for(i = 0; i < vec[u].size(); i++)
    			{
    				v = vec[u][i];
    				if(!d[v]) add(v, u, 1e9), add(u, v, 0);
    			}
    		}
    	printf("%d
    ", sum - dinic());
    	return 0;
    }
    

      

  • 相关阅读:
    hdoj2159【二位费用背包】
    POJ2367【拓扑排序】
    POJ2371【水题】
    POJ2369【循环节】
    POJ2370【水题】
    POJ2365【几何】
    POJ2366【二分】
    POJ1276【多重背包】
    瞎说一波3种基本背包问题【希望巨巨们指出错误】
    Codeforces 550B 【暴力】
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/8249305.html
Copyright © 2011-2022 走看看