版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/zzk_233/article/details/82939523
最坏情况下每个’.’都要放一支军队,但是事实是有些’.’可以不放因为可以利用前面的军队移动过来,
所以答案就可以表示为’.’的数量减掉最多可以节约多少只军队。
由于每个’.’只能最多有一个前驱和一个后继(由一个点转移而来,也只能转移向一个点),
所以我们将原图拆点,每个格点拆成一个入点和一个出点,出点向可到达的入点连边,就形成了一个二分图,
求此图的最大匹配即为最多可节约的军团数量。(PS:匈牙利算法真好用)。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
char s[55][55];
int n,m,r,c,x,y,ans;
int check(int a,int b)
{
if(a<=n&&a>=1&&b<=m&&b>=1)
{
return 1;
}
return 0;
}
int has(int a,int b)
{
return (a-1)*m+b;
}
struct node
{
int to;
int nxt;
}edge[20005];
int head[3005];
int cnt = 1;
void init()
{
memset(head,-1,sizeof(head));
}
void add(int from,int to)
{
edge[cnt].to = to;
edge[cnt].nxt = head[from];
head[from] = cnt++;
}
int used[3005],girl[3005];
int Hungary(int u)
{
used[u] = 1;
for(int i = head[u];i != -1;i = edge[i].nxt)
{
int to = edge[i].to;
if(!used[to])
{
used[to] = 1;
if(!girl[to] || Hungary(girl[to]))
{
girl[to] = u;
return 1;
}
}
}
return 0;
}
int main()
{
scanf("%d%d%d%d", &n, &m, &r, &c);
init();
int ru[4][2]={r,c,r,-c,c,r,c,-r};
for(int i = 1;i <= n;i++)scanf("%s",s[i]+1);
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
if(s[i][j] == '.')
{
for(int k = 0;k < 4;k++)
{
x=i+ru[k][0];
y=j+ru[k][1];
if(check(x,y) && s[x][y] == '.')
{
add(has(i,j),has(x,y));
}
}
}
}
}
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
if(s[i][j] == '.')
{
memset(used,0,sizeof(used));
if(Hungary(has(i,j)) == 0)
{
ans++;
}
}
}
}
printf("%d",ans);
return 0;
}