P3355 骑士共存问题

Posted garen-wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 - cnt - dinic());
    return 0;
}

以上是关于P3355 骑士共存问题的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P3355 骑士共存问题

P3355 骑士共存问题 二分建图 + 当前弧优化dinic

luogu P3355 骑士共存问题

洛谷 P3355 骑士共存问题最小割

P3355 骑士共存问题

P3355 骑士共存问题最小点覆盖网络流24题