【LG-P2472 [SCOI2007]】蜥蜴 (最大网络流)

传送门:P2472 [SCOI2007]蜥蜴

最大网络流(建图复杂)

此题外附一个当前弧优化的运用。

除建图外,其余都是 Dinic \text{Dinic} Dinic 板子了。

  1. 石柱内部建两个点,一个入口,一个出口, 容量为其高度;

  2. 如果可以一步跳出地图,就和汇点连一条边;

  3. 源点和木桩连边,因为一个木桩上只有一只蚂蚱,所以容量为 1;

  4. 若木桩 A 到木桩 B 能一步跳到,就在它们之间连边,容量为 inf \text{inf} inf

代码 + 注释

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;

#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define maxn 25
#define maxm 100005//数组需开大 
#define inf 2147483647
int n, m, d, nm;
int c[maxn][maxn], cntc, l[maxm], r[maxm], ans;
int s, t, p[maxn][maxn], tot;
int dep[maxm];
int hd[maxm], cur[maxm], cnt = 1;
struct node{
	int to, nxt, w;
}e[maxm << 1];
struct animl{
	int lie, hng;
};
vector <animl> an;

inline void add(int u, int v, int w)
{
	e[++cnt].to = v;
	e[cnt].nxt = hd[u], e[cnt].w = w;
	hd[u] = cnt;
	e[++cnt].to = u;
	e[cnt].nxt = hd[v], hd[v] = cnt;
}

inline int dist(int x, int y, int a, int b)
{
	return (x - a) * (x - a) + (y - b) * (y - b);
}

inline bool bfs()
{
	queue <int> q;
	memset(dep, 0, sizeof dep);
	dep[s] = 1, q.push(s);
	while(!q.empty())
	{
		int u = q.front();
		q.pop();
		for(int v, i = hd[u]; i; i = e[i].nxt)
		{
			if(!dep[v = e[i].to] and e[i].w)
			{
				dep[v] = dep[u] + 1;
				q.push(v);
			}                              
		}
	}
	return dep[t] ? true : false;
}

inline int dinic(int u, int in)
{
	if(u == t or !in) return in;
	int out = 0;
	for(int v, &i = cur[u]/*cur[u] 随着 i 的变化而变化*/; i and in/*注意判容量剩余*/; i = e[i].nxt)
	        /*当前弧优化*/ 
	{
		if(dep[v = e[i].to] == dep[u] + 1 and e[i].w)
		{
			int res = dinic(v, min(in, e[i].w));
			e[i].w -= res, e[i ^ 1].w += res;
			in -= res, out += res;
		}
	}
	if(!out) dep[u] = 0;
	return out;
}

int main()
{
	//输入 
	scanf("%d %d %d", &n, &m, &d);
	nm = n * m, t = nm * 2 + 1;
	rep(i, 1, n) rep(j, 1, m)
	{
		p[i][j] = ++tot;
		char ch;
		cin >> ch;
		c[i][j] = ch - 48;
		if(c[i][j]) l[++cntc] = i, r[cntc] = j;
	}
	rep(i, 1, n) rep(j, 1, m)
	{
		char ch;
		cin >> ch;
		if(ch == 'L')
			an.push_back((animl){j, i}/*注意顺序*/);
	}
	
	//建图: 
	rep(i, 1, cntc)
	{
		int L = l[i], R = r[i];
		add(p[L][R], p[L][R] + nm, c[L][R]);//1.石柱内部建两个点,一个入口,一个出口, 容量为其高度 
		if(L <= d or R <= d or L + d > n or R + d > m)
			add(p[L][R] + nm, t, inf);//2.如果可以一步跳出地图,就和汇点连一条边 
	}
	rep(i, 0, an.size() - 1)
		add(s, p[an[i].hng][an[i].lie], 1);//3.源点和木桩连边,因为一个木桩上只有一只蚂蚱,所以容量为 1 
	rep(i, 1, cntc) rep(j, 1, cntc)
	{
		if(d * d >= dist(l[i], r[i], l[j], r[j]) and i != j)
			add(p[l[i]][r[i]] + nm, p[l[j]][r[j]], inf);//4.木桩和木桩之间连边,容量为 Inf 
	}
	 
	while(bfs())//Dinic板子 
	{
		rep(i, s, t) cur[i] = hd[i];//当前弧优化-数组初始化 
		ans += dinic(s, inf);
	}
	printf("%d\n", an.size() - ans);
	return 0; 
}

—— E n d End End——

posted @ 2022-03-25 07:25  pldzy  阅读(27)  评论(0)    收藏  举报