题解:P10939 骑士放置

分析

前置知识:网络流最小割

套路题。

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

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

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

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

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

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

连边方法如下:

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

最后的结果就是 nmtmaxflow

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

所以最终的时间复杂度应为 O(n2)

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();
}

本文作者:Jimmy-LEEE

本文链接:https://www.cnblogs.com/redacted-area/p/18429462

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Jimmy-LEEE  阅读(3)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起