传送门:洛谷 P1263
从前有一个王国,这个王国的城堡是一个矩形,被分为M×N个方格。一些方格是墙,而另一些是空地。这个王国的国王在城堡里设了一些陷阱,每个陷阱占据一块空地。
一天,国王决定在城堡里布置守卫,他希望安排尽量多的守卫。守卫们都是经过严格训练的,所以一旦他们发现同行或同列中有人的话,他们立即向那人射击。因此,国王希望能够合理地布置守卫,使他们互相之间不能看见,这样他们就不可能互相射击了。守卫们只能被布置在空地上,不能被布置在陷阱或墙上,且一块空地只能布置一个守卫。如果两个守卫在同一行或同一列,并且他们之间没有墙的话,他们就能互相看见。(守卫就像象棋里的车一样)
你的任务是写一个程序,根据给定的城堡,计算最多可布置多少个守卫,并设计出布置的方案。
除去墙的存在,这个就是标准的二分图模型了,横纵坐标连边即可。
本题同理,只需要处理一下入读即可,有墙的话,视为换行/列。
方案输出:匹配的时候顺便记录匹配边即可。读入的时候记录一下边所代表的点。
#include
#include
#include
#define IL inline
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
int n, m;
int mp[205][205];
int px[205][205];
struct node
{
int x, y;
IL node(int x_ = 0, int y_ = 0)
{
x = x_; y = y_;
}
}pos[40005];
int to[40005], nxt[40005];
int cnt, last[20005];
IL void add(int u, int v)
{
to[++cnt] = v; nxt[cnt] = last[u]; last[u] = cnt;
}
int match[20005];
int mark[20005];
bool vis[20005];
IL bool dfs(int u)
{
for(int i = last[u], v; (v = to[i]); i = nxt[i])
if(!vis[v])
{
vis[v] = 1;
if(!match[v] || dfs(match[v]))
{
match[v] = u;
mark[v] = i;
return 1;
}
}
return 0;
}
IL int max_flow()
{
int sum = 0;
for(int i = 1; i <= m; ++i)
{
memset(vis, 0, sizeof(vis));
if(dfs(i)) ++sum;
}
return sum;
}
IL void wri()
{
for(int i = 1; i <= n; ++i)
if(mark[i])
printf("%d %d\n", pos[mark[i]].x, pos[mark[i]].y);
}
int main()
{
int l = read(), c = read();
for(int i = 1, flag; i <= l; ++i)
{
flag = 1;
for(int j = 1; j <= c; ++j)
{
mp[i][j] = read();
if(mp[i][j] == 2) flag = 1; else
if(!mp[i][j])
{
if(flag) { ++n; flag = 0; }
px[i][j] = n;
}
}
}
for(int j = 1, flag; j <= c; ++j)
{
flag = 1;
for(int i = 1; i <= l; ++i)
{
if(mp[i][j] == 2) flag = 1; else
if(!mp[i][j])
{
if(flag) { ++m; flag = 0; }
add(m, px[i][j]); pos[cnt] = node(i, j);
}
}
}
printf("%d\n", max_flow());
wri();
return 0;
}