W
e
l
c
o
m
e
: )

题解:P10939 骑士放置

分析

前置知识:网络流最小割

套路题。

在这道题基础上有很多改版,比如长脖子鹿放置

首先黑白染色。\((n=m=4)\)

保证染色后同种颜色上的骑士不能互相攻击。

1 0 1 0
0 1 0 1
1 0 1 0
0 1 0 1

染色之后考虑将原题转化为最小割问题。

也就是说在棋盘上放满骑士后再考虑扔掉一些棋子。

连边方法如下:

  • 从白格向到它能攻击到的黑格连边,边权为 \(\infty\)
  • 从原点 \(S\)能放置的白格连边权为 \(1\) 的边。
  • 能放置的黑格向汇点 \(T\) 连边权为 \(1\) 的边。

最后的结果就是 \(nm-t-\operatorname{maxflow}\)

如果用 Dinic,令 \(n\) 为点数,\(m\) 为边数,其在二分图上最差时间复杂度为 \(O(n\sqrt{m})\)。(可惜我不会证)

所以最终的时间复杂度应为 \(O(n^2)\)

Code

这里使用最高标号预流推进 HLPP

#include<bits/stdc++.h>
using namespace std;

template<typename Tp, size_t sizn, size_t sizm>
struct netflow
{
    int cnt=1, s=sizn-3, t=sizn-2;
    Tp val[sizm<<1], dis[sizn];

    void link(int u, int v, Tp w) 
    {
        to [++cnt]=v;       val [cnt]=w;
        nxt[ cnt ]=head[u]; head[ u ]=cnt;
        to [++cnt]=u;       val [cnt]=0;
        nxt[ cnt ]=head[v]; head[ v ]=cnt;
    }


    int head[sizn], to[sizm<<1], nxt[sizm<<1], now[sizm<<1];
    const Tp inf=((Tp)INFINITY)>>1;
    int bfs() 
    {
        for(int i=1;i<sizn;i++) dis[i]=inf;
        queue<int> q;
        q.push(s);
        dis[s]=0;
        now[s]=head[s];
        while (!q.empty())
        {
            int idx=q.front(); q.pop();
            for(int i=head[idx];i;i=nxt[i])
            {
                int arr=to[i];
                if(val[i]>0&&dis[arr]==inf)
                {
                    q.push(arr);
                    now[arr]=head[arr];
                    dis[arr]=dis [idx]+1;
                    if(arr==t) return 1;
                }
            }
        }
        return 0;
    }
    
    Tp dfs(int idx, Tp sum)
    {
        if(idx==t) return sum;
        Tp k, res=0;
        for(int i=now[idx];i&&sum;i=nxt[i])
        {
            now[idx]=i;
            int arr=to[i];
            if(val[i]>0&&(dis[arr]==dis[idx]+1))
            {
                k=dfs(arr, min(sum, val[i]));
                if(k==0) dis[arr]=inf;
                val[i]-=k;      res+=k;
                val[i^1]+=k;    sum-=k;
            }
        }
        return res;
    }

    Tp maxflow()
    {
        Tp ans=0;
        while (bfs()) ans+=dfs(s, inf); 
        return ans;
    }
};

netflow<int, 50000, 1000000> nf;

#define maxn 202
int blk[maxn][maxn];
#define pos(i, j) (((i)-1)*m+(j))

int dx[]={1, -1, 1, -1, 2, -2, 2, -2};
int dy[]={2, 2, -2, -2, 1, 1, -1, -1};

#define chk(i, j) ((i)>0&&(j)>0&&(i)<=n&&(j)<=m)

int main()
{
    int n, m, t;
    cin>>n>>m>>t;
    for(int i=1, a, b;i<=t;i++)
    {
        cin>>a>>b;
        blk[a][b]=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(blk[i][j]) continue;
            if((i+j)&1) nf.link(nf.s, pos(i, j), 1);
            else {nf.link(pos(i, j), nf.t, 1);continue;}
            
            for(int k=0;k<8;k++)
            {
                int nx=i+dx[k];
                int ny=j+dy[k];
                if(!chk(nx, ny)||blk[nx][ny]) continue;
                nf.link(pos(i, j), pos(nx, ny), nf.inf);
            }
        }
    cout<<n*m-t-nf.maxflow();

}
posted @ 2024-09-24 16:31  Jimmy-LEEE  阅读(10)  评论(0)    收藏  举报