Part 1. 题意
在 \(N \times 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\) 面墙与 \(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 ();
}