Part 1. 题意
在 N × M N \times M N×M 的矩阵中的空地放人机,任一人机上下左右走到边界或墙之前遇不到另一人机。
我已经尽力写得简短了。。
Part 2. 思路
我们先思考无墙的情况。
若无墙,则同車的放置,把草方块当作禁止放車的方块即可,。
贴一下车的放置的代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,t,ans,g[210][210],mat[210];
bool vis[210];
bool match (int u) {
for (int i=1;i<=m;i++)
if (!g[u][i]&&!vis[i]) {
vis[i]=1;
if (!mat[i]||match (mat[i])) {
mat[i]=u;
return 1;
}
}
return 0;
}
int main () {
cin>> n>> m>> t;
for (int i=1,x,y;i<=t;i++) {
cin>> x>> y;
g[x][y]=1;
}
for (int i=1;i<=n;i++) {
memset (vis,0,sizeof (vis));
if (match (i))
ans++;
}
cout<< ans;
return 0;
}
而此题多了墙这种阻挡方块,怎么办?
显然,对于每一行和每一列,每多一个墙方块,就可以多放一个人机,如下两图(白色为空地,红色为人机,绿色为草地,棕色为墙):
上两例均有 2 2 2 面墙与 3 3 3 个人机。
所以我们可以对于行的可放人机区域和列的可放人机区域分别计数,将每个空地计算出的行区域数作为左部点,列区域数作为右部点,建立二部图,跑最大匹配即可。
Part3. 本题代码
#include <bits/stdc++.h>
using namespace std;
int t=-1,s,n,m,lk,ck,ans,mat[2510],ls[60][60],cs[60][60];
bool vis[2510];
char mp[60][60],buf[1024];
vector<int> g[2510];
bool match (int u) {
for (int v: g[u])
if (!vis[v]) {
vis[v]=1;
if (!mat[v]||match (mat[v])) {
mat[v]=u;
return 1;
}
}
return 0;
}
int main () {
if (!~t) cin>> t;
if (!t--) return 0;
cin>> n>> m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
cin>> mp[i][j];
lk=ck=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
ls[i][j]=(lk+=(j==1||mp[i][j-1]=='#'));
for (int j=1;j<=m;j++)
for (int i=1;i<=n;i++)
cs[i][j]=(ck+=(i==1||mp[i-1][j]=='#'));
for (int i=1;i<=lk;i++)
g[i].clear ();
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (mp[i][j]=='o')
g[ls[i][j]].push_back (cs[i][j]);
ans=0;
memset (mat,0,sizeof (mat));
for (int i=1;i<=lk;i++) {
memset (vis,0,sizeof (vis));
ans+=match (i);
}
sprintf (buf,"Case :%d\n%d",++s,ans);
puts (buf);
return main ();
}