[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;
}

  

原文地址:https://www.cnblogs.com/zhenghaotian/p/8249305.html