P3355 骑士共存问题

二分图最大独立集

先给出二分图最大独立集的概念:选择最多的点,使任何边的两边不被同时选中。

并且有结论:最大独立集=节点总数-最大匹配。

这道题为什么是二分图?

我们可以通过\((x,y)\)中的\(x+y\)的奇偶性来构造二分图,显然它们肯定不会互相攻击。

当一个点\(x+y\)为奇时,向它能攻击到的点都连一条权值为1的边。

这就是这个二分图的建图方法。

但是我不会匈牙利算法,直接网络流套下去就行了。

注意:那些障碍点对我们整个计算根本没有影响,直接忽略它们就可以了。节点总数也不用计算它们。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 205, maxN = 40005;
const int INF = 0x3f3f3f3f;
const int dx[] = {-1, 1, -2, 2, -2, 2, -1, 1};
const int dy[] = {-2, -2, -1, -1, 1, 1, 2, 2};
struct Edges
{
	int next, to, weight;
} e[4000005];
int head[maxN], tot = 1;
bool b[maxn][maxn];
int dep[maxN], cur[maxN];
int queue[maxN << 1], front, rear;
int n, m;
int s, t;
int cnt;
int id(int x, int y)
{
	return (x - 1) * n + y;
}
void link(int u, int v, int w)
{
	e[++tot] = (Edges){head[u], v, w};
	head[u] = tot;
}
void addEdges(int u, int v, int w)
{
	link(u, v, w);
	link(v, u, 0);
}
bool bfs()
{
	memset(dep, 0, sizeof dep);
	front = rear = 0;
	dep[s] = 1;
	queue[rear++] = s;
	while(front < rear)
	{
		int u = queue[front++];
		for(int i = head[u]; i; i = e[i].next)
		{
			int v = e[i].to;
			if(e[i].weight > 0 && !dep[v])
			{
				dep[v] = dep[u] + 1;
				queue[rear++] = v;
			}
		}
	}
	return dep[t];
}
int dfs(int u, int flow)
{
	if(u == t) return flow;
	for(int &i = cur[u]; i; i = e[i].next)
	{
		int v = e[i].to;
		if(e[i].weight > 0 && dep[v] == dep[u] + 1)
		{
			int di = dfs(v, std::min(flow, e[i].weight));
			if(di > 0)
			{
				e[i].weight -= di;
				e[i ^ 1].weight += di;
				return di;
			}
		}
	}
	return 0;
}
int dinic()
{
	int ans = 0;
	while(bfs())
	{
		for(int i = 1; i <= t; i++) cur[i] = head[i];
		while(int temp = dfs(s, INF)) ans += temp;
	}
	return ans;
}
int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= n; j++)
		{
			int temp; scanf("%1d", &temp);
			b[i][j] = temp;
			if(temp) cnt++;
		}
	}
	s = n * n + 1, t = s + 1;
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= n; j++)
		{
			if(b[i][j]) continue;
			if((i + j) % 2)
			{
				addEdges(s, id(i, j), 1);
				for(int k = 0; k < 8; k++)
				{
					int nx = i + dx[k], ny = j + dy[k];
					if(nx >= 1 && nx <= n && ny >= 1 && ny <= n)
					{
						addEdges(id(i, j), id(nx, ny), 1);
					}
				}
			}
			else
			{
				addEdges(id(i, j), t, 1);
			}
		}
	}
	printf("%d\n", n * n - cnt - dinic());
	return 0;
}
posted @ 2018-10-27 07:58  Garen-Wang  阅读(151)  评论(0编辑  收藏  举报