bzoj 2150

然后考虑正解

我们发现,最坏情况就是每个点都派驻军队,所以答案至多是“.”的数目

而且,每个点都至多只有一个入度和一个出度,所以我们可以将每个点拆成两个点,一个作为入点,一个作为出点,然后所有图上能到达的点由出点向入点建图

这样整个图就形成了一个二分图

然后在整个图上跑二分图匹配即可

答案即为“.”点数-二分图最大匹配数

稍微证明一下:我们的目的是最大化有入边的点的数量,那我们仅需让入点能更多的被匹配上即可

那也就是二分图匹配喽

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
struct Edge
{
int next;
int to;
}edge[];
int head[];
int maps[][];
char s[];
bool used[];
int f[];
int n,m,r,c;
int cnt=,cot;
queue <int> Q;
bool check(int x,int y)
{
if(x>&&x<=n&&y>&&y<=m&&maps[x][y])
{
return ;
}
return ;
}
void init()
{
memset(head,-,sizeof(head));
cnt=;
}
void add(int l,int r)
{
edge[cnt].next=head[l];
edge[cnt].to=r;
head[l]=cnt++;
}
int po(int x,int y)
{
return (x-)*m+y;
}
int ppo(int x,int y)
{
return (x-)*m+y+n*m;
}
bool dfs(int x)
{
for(int i=head[x];i!=-;i=edge[i].next)
{
int to=edge[i].to;
if(used[to])
{
continue;
}
used[to]=;
if(!f[to]||dfs(f[to]))
{
f[to]=x;
return ;
}
}
return ;
}
int hungary()
{
int ret=;
while(!Q.empty())
{
memset(used,,sizeof(used));
int u=Q.front();
Q.pop();
if(dfs(u))
{
ret++;
}
}
return ret;
}
int main()
{
freopen("legion.in","r",stdin);
freopen("legion.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&r,&c);
init();
for(int i=;i<=n;i++)
{
scanf("%s",s+);
for(int j=;j<=m;j++)
{
if(s[j]=='.')
{
maps[i][j]=;
Q.push(po(i,j));
cot++;
}else
{
maps[i][j]=;
}
}
}
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
int x0=i+r;
int y0=j+c;
if(check(x0,y0))
{
add(po(i,j),ppo(x0,y0));
}
x0=i+r;
y0=j-c;
if(check(x0,y0))
{
add(po(i,j),ppo(x0,y0));
}
x0=i+c;
y0=j+r;
if(check(x0,y0))
{
add(po(i,j),ppo(x0,y0));
}
x0=i+c;
y0=j-r;
if(check(x0,y0))
{
add(po(i,j),ppo(x0,y0));
}
}
}
printf("%d\n",cot-hungary());
return ;
}
上一篇:(译)ABP之Entities


下一篇:Storm笔记——技术点汇总