题意:
在一个Y行X列的网格里有空地(.),重要位置(*)和障碍物(#),用最少的机器人看守所有重要位置,每个机器人要放在一个格子里,面朝上下左右4个方向之一。机器人会发出激光,一直射到障碍物为止,沿途都是看守范围。
思路:
每个点就是把x,y连在一起,选取最少点覆盖所有的x,y,那么就是个二分图匹配,左边是x,右边是y。有障碍物,所以需要拆点,重新赋值行和列,每碰见一个障碍物,就将后面的所有东西移动到下一行,这样就不会有障碍物了。
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
#define fi first
#define se second
#define pii pair<int,int>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 100+5;
int row, col;
int book[maxn][maxn], G[maxn][maxn];
pii Gt[maxn][maxn];
int cy[maxn];
bool visy[maxn];
bool dfs(int u){
for(int i = 0; i <= col; ++i){
if(!visy[i]&&G[u][i]){
visy[i] = 1;
if(cy[i] == -1||dfs(cy[i])){
cy[i] = u;
return true;
}
}
}
return false;
}
int Maxmatch(){
memset(cy, -1, sizeof(cy));
int ans = 0;
for(int i = 0; i <= row; ++i){
memset(visy, 0, sizeof(visy));
if(dfs(i)) ++ans;
}
return ans;
}
int main()
{
freopen("in.txt","r",stdin);
int T, h, w, blocks, pots; scanf("%d",&T);
while(T--){
memset(book, 0, sizeof(book));
memset(G, 0, sizeof(G));
scanf("%d%d",&h,&w);
scanf("%d",&pots); // 重要的点
for(int i = 0; i < pots; ++i){
int x,y; scanf("%d%d",&x,&y);
book[x-1][y-1] = 1;
}
scanf("%d",&blocks); // 障碍数
for(int i = 0; i < blocks; ++i){
int x,y; scanf("%d%d",&x,&y);
book[x-1][y-1] = 2;
}
// 建图
row = -1;
bool flag;
for(int i = 0; i < h; ++i){
flag = true;
for(int j = 0; j < w; ++j){
if(1 == book[i][j]){
if(flag) ++row;
Gt[i][j].fi = row;
flag = false;
}
else if(2 == book[i][j]) flag = true;
}
}
col = -1;
for(int j = 0; j < w; ++j){
flag = true;
for(int i = 0; i < h; ++i){
if(1 == book[i][j]){
if(flag) ++col;
Gt[i][j].se = col;
flag = false;
}
else if(2 == book[i][j]) flag = true;
}
}
for(int i = 0; i < h; ++i)
for(int j = 0; j < w; ++j) if(1 == book[i][j]) G[Gt[i][j].fi][Gt[i][j].se] = 1;
//printf("row = %d, col = %d\n",row,col);
int ans = Maxmatch();
printf("%d\n",ans);
}
return 0;
}