蜜汁互测题...
有一个思路是显而易见的:爆搜!
期望得分30
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
bool maps[55][55];
bool used[55][55];
char s[55];
int m,n,r,c;
int cnt=1;
bool check(int x,int y)
{
if(x>0&&x<=n&&y>0&&y<=m&&maps[x][y]&&!used[x][y])
{
return 1;
}
return 0;
}
int ans=0x3f3f3f3f;
void dfs(int x,int y,int tempcnt)
{
int x0=x+r;
int y0=y+c;
bool flag1=0;
if(check(x0,y0))
{
used[x0][y0]=1;
dfs(x0,y0,tempcnt);
used[x0][y0]=0;
flag1=1;
}
x0=x+c;
y0=y+r;
bool flag2=0;
if(check(x0,y0))
{
used[x0][y0]=1;
dfs(x0,y0,tempcnt);
used[x0][y0]=0;
flag2=1;
}
x0=x+c;
y0=y-r;
bool flag3=0;
if(check(x0,y0))
{
used[x0][y0]=1;
dfs(x0,y0,tempcnt);
used[x0][y0]=0;
flag3=1;
}
x0=x+r;
y0=y-c;
bool flag4=0;
if(check(x0,y0))
{
used[x0][y0]=1;
dfs(x0,y0,tempcnt);
used[x0][y0]=0;
flag4=1;
}
if(!flag1&&!flag2&&!flag3&&!flag4)
{
bool flag5=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(check(i,j))
{
used[i][j]=1;
dfs(i,j,tempcnt+1);
used[i][j]=0;
flag5=1;
break;
}
}
if(flag5)
{
break;
}
}
if(!flag5)
{
ans=min(ans,tempcnt);
}
}
}
int main()
{
freopen("legion.in","r",stdin);
freopen("legion.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&r,&c);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
{
if(s[j]=='.')
{
maps[i][j]=1;
}else
{
maps[i][j]=0;
}
}
}
bool flag=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(check(i,j))
{
used[i][j]=1;
dfs(i,j,1);
flag=1;
break;
}
}
if(flag)
{
break;
}
}
printf("%d\n",ans);
return 0;
}
然后考虑正解
我们发现,最坏情况就是每个点都派驻军队,所以答案至多是“.”的数目
而且,每个点都至多只有一个入度和一个出度,所以我们可以将每个点拆成两个点,一个作为入点,一个作为出点,然后所有图上能到达的点由出点向入点建图
这样整个图就形成了一个二分图
然后在整个图上跑二分图匹配即可
答案即为“.”点数-二分图最大匹配数
稍微证明一下:我们的目的是最大化有入边的点的数量,那我们仅需让入点能更多的被匹配上即可
那也就是二分图匹配喽
#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[10005];
int head[2505];
int maps[55][55];
char s[55];
bool used[6005];
int f[6005];
int n,m,r,c;
int cnt=1,cot;
queue <int> Q;
bool check(int x,int y)
{
if(x>0&&x<=n&&y>0&&y<=m&&maps[x][y])
{
return 1;
}
return 0;
}
void init()
{
memset(head,-1,sizeof(head));
cnt=1;
}
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-1)*m+y;
}
int ppo(int x,int y)
{
return (x-1)*m+y+n*m;
}
bool dfs(int x)
{
for(int i=head[x];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(used[to])
{
continue;
}
used[to]=1;
if(!f[to]||dfs(f[to]))
{
f[to]=x;
return 1;
}
}
return 0;
}
int hungary()
{
int ret=0;
while(!Q.empty())
{
memset(used,0,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=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
{
if(s[j]=='.')
{
maps[i][j]=1;
Q.push(po(i,j));
cot++;
}else
{
maps[i][j]=0;
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;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 0;
}