[洛谷 P1263] 宮廷守衛 --- 二分圖最大匹配
阿新 • • 發佈:2018-12-17
題目描述
從前有一個王國,這個王國的城堡是一個矩形,被分為M×N個方格。一些方格是牆,而另一些是空地。這個王國的國王在城堡裡設了一些陷阱,每個陷阱佔據一塊空地。
一天,國王決定在城堡里布置守衛,他希望安排儘量多的守衛。守衛們都是經過嚴格訓練的,所以一旦他們發現同行或同列中有人的話,他們立即向那人射擊。因此,國王希望能夠合理地佈置守衛,使他們互相之間不能看見,這樣他們就不可能互相射擊了。守衛們只能被佈置在空地上,不能被佈置在陷阱或牆上,且一塊空地只能佈置一個守衛。如果兩個守衛在同一行或同一列,並且他們之間沒有牆的話,他們就能互相看見。(守衛就像象棋裡的車一樣)
你的任務是寫一個程式,根據給定的城堡,計算最多可佈置多少個守衛,並設計出佈置的方案。
分析
除去牆的存在,這個就是標準的二分圖模型了,橫縱座標連邊即可。 本題同理,只需要處理一下入讀即可,有牆的話,視為換行/列。 方案輸出:匹配的時候順便記錄匹配邊即可。讀入的時候記錄一下邊所代表的點。
程式碼
#include <cstdio>
#include <cstdlib>
#include <cstring>
#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;
}