题解: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&∑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();
}

浙公网安备 33010602011771号