1. 程式人生 > >P3355 騎士共存問題

P3355 騎士共存問題

問題 網絡流 就是 cst else include ges 這就是 二分

二分圖最大獨立集

先給出二分圖最大獨立集的概念:選擇最多的點,使任何邊的兩邊不被同時選中。

並且有結論:最大獨立集=節點總數-最大匹配。

這道題為什麽是二分圖?

我們可以通過\((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;
}

P3355 騎士共存問題