【Vijos 1607】【NOI 2009】植物大战僵尸

https://vijos.org/p/1607
vijos界面好漂亮O(∩_∩)O~~
对于一个植物x,和一个它保护的植物y,连一条边<x,y>表示x保护y,对于每个植物再向它左方的植物也连一条边,很明显能连出一个图,图中的边<x,y>的含义为如果要吃y,就必须先吃x。
这个图的强连通分量中的植物永远不会被吃,而且强联通分量中的植物连出去的边能到达的任何植物都不会被吃。
本来想先tarjan然后再dfs,然后DaD3zZ用拓扑序教我做人qwq
所有入度为0的点可以被吃,入读为0的点连出去的且不再强连通分量中的点也可以被吃,拓扑一下就好了。
把可以被吃的点拿出来就是一个最大权闭合图问题了,最小割解决。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 633;
const int inf = 0x7fffffff;

bool can[N];
int cur[N], qu[N], id[23][33], n, m, cnt = 0, tot = 0, score[N], point[N], point2[N], in[N];

struct node {int nxt, to, c;} E[N * N];
struct node2 {int nxt, to;} G[N * N];

void ins(int u, int v, int c) {E[++cnt] = (node) {point[u], v, c}; point[u] = cnt;}
void ins2(int u, int v) {G[++cnt] = (node2) {point2[u], v}; point2[u] = cnt; ++in[v];}

int d[N];
bool BFS(int s, int t) {
	memset(d, 0, sizeof(int) * (t + 1));
	int p = 0, q = 1; qu[1] = s; d[s] = 1;
	while (p != q) {
		int u = qu[++p];
		for (int i = point[u]; i; i = E[i].nxt)
			if (E[i].c && d[E[i].to] == 0) {
				d[E[i].to] = d[u] + 1;
				qu[++q] = E[i].to;
			}
	}
	return d[t];
}

int S, T;
int dfs(int u, int a) {
	if (u == T || !a) return a;
	int f, flow = 0;
	for (int &i = cur[u]; i; i = E[i].nxt)
		if (d[E[i].to] == d[u] + 1 && (f = dfs(E[i].to, min(a, E[i].c)))) {
			flow += f; E[i].c -= f; E[i ^ 1].c += f; a -= f;
			if (!a) break;
		}
	return flow;
}

int dinic(int s, int t) {
	int flow = 0;
	while (BFS(s, t)) {
		for (int i = 1; i <= t; ++i) cur[i] = point[i];
		flow += dfs(s, inf);
	}
	return flow;
}

int main() {
	scanf("%d%d", &n, &m);
	int s, x, y;
	for (int i = 0; i < n; ++i)
		for (int j = 0; j < m; ++j)
			id[i][j] = ++tot;
	for (int i = 0; i < n; ++i)
		for (int j = 0; j < m; ++j) {
			scanf("%d%d", score + id[i][j], &s);
			for (int k = 0; k < s; ++k) {
				scanf("%d%d", &x, &y);
				ins2(id[i][j], id[x][y]);
			}
		}
	for (int i = 0; i < n; ++i)
		for (int j = 1; j < m; ++j)
			ins2(id[i][j], id[i][j - 1]);
	
	int head = 0, tail = 0;
	for (int i = 0; i < n; ++i)
		if (in[id[i][m - 1]] == 0)
			qu[++tail]= id[i][m - 1];
	
	while (head != tail) {
		int u = qu[++head]; can[u] = true;
		for (int i = point2[u]; i; i = G[i].nxt)
			if (--in[G[i].to] == 0)
				qu[++tail] = G[i].to;
	}
	
	cnt = 1;
	for (int i = 1; i <= tot; ++i)
		if (can[i])
			for (int j = point2[i]; j; j = G[j].nxt)
				if (can[G[j].to]) {
					ins(G[j].to, i, inf);
					ins(i, G[j].to, 0);
				}
	
	int ans = 0; S = tot + 1, T = S + 1;
	for (int i = 1; i <= tot; ++i)
		if (can[i]) {
			if (score[i] > 0) {
				ans += score[i];
				ins(S, i, score[i]);
				ins(i, S, 0);
			} else if (score[i] < 0) {
				ins(i, T, -score[i]);
				ins(T, i, 0);
			}
		}
	printf("%d\n", ans - dinic(S, T));
	return 0;
}
posted @ 2017-03-28 15:45  abclzr  阅读(294)  评论(0编辑  收藏  举报