题目
题意:
n*m的矩形格子中有一些宝藏,有些点不能经过,每次可以取走一横行,或者一纵行的宝藏,求至少需要多少次取走所有宝藏
题解:
如果没有不能走的点,就是一道经典的二分图匹配的最小点覆盖。考虑障碍,在同一行(或列)被障碍隔开的点就不能算同一行(或列),所以重置坐标即可,进行二分图匹配。
代码:
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; #define maxn 105 #define maxm 5005 int n,m,k,N,M; int g[maxn][maxn],xx[maxn][maxn],yy[maxn][maxn],result[maxm]; bool e[maxm][maxm],state[maxm]; int find(int x) { for (int i=1;i<=M;i++) if (!state[i]&&e[x][i]) { state[i]=1; if (!result[i]||find(result[i])) { result[i]=x; return 1; } } return 0; } int hungry() { int res=0; memset(result,0,sizeof(result)); for (int i=1;i<=N;i++) { memset(state,0,sizeof(state)); if (find(i)) res++; } return res; } int main() { //freopen("/home/moor/Code/input","r",stdin); int cas,x,y; scanf("%d",&cas); while (cas--) { scanf("%d%d",&n,&m); scanf("%d",&k); memset(g,0,sizeof(g)); for (int i=1;i<=k;i++) { scanf("%d%d",&x,&y); g[x][y]=1; } scanf("%d",&k); for (int i=1;i<=k;i++) { scanf("%d%d",&x,&y); g[x][y]=2; } N=0; for (int i=1;i<=n;i++) { int j=1; while (j<=m) { N++; while (j<=m&&g[i][j]!=2) xx[i][j++]=N; while (j<=m&&g[i][j]==2) j++; } } M=0; for (int i=1;i<=m;i++) { int j=1; while (j<=n) { M++; while (j<=n&&g[j][i]!=2) yy[j++][i]=M; while (j<=n&&g[j][i]==2) j++; } } memset(e,0,sizeof(e)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (g[i][j]==1) e[xx[i][j]][yy[i][j]]=1; printf("%d\n",hungry()); } return 0; }