# [SMOJ2213]停车场

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <queue>

using namespace std;

typedef pair <int, int> pii;

const int MAXN = 200 + 10;
const int dx[] = {-1, 1, 0, 0};
const int dy[] = {0, 0, -1, 1};
const int INF = 0x3f3f3f3f;

struct Edge {
Edge *next;
int cap;
int dest;
} edges[MAXN * MAXN], *current, *first_edge[MAXN];

int n, m, s, t;
char matrix[MAXN][MAXN]; int rev[MAXN][MAXN]; //若 (i, j) 为停车场，则 rev[i][j] 为该停车场在 parks 数组中的下标

int cnt_cars, cnt_parks, dis[MAXN][MAXN]; //dis[i][j] 为第 j 辆车到第 i 个停车场的距离
pii cars[MAXN], parks[MAXN];

bool vis[MAXN][MAXN], vis2[MAXN]; //分别为 bfs 和 dfs 服务

void bfs(int car_id) { //预处理第 car_id 辆车到停车场的距离
queue < pair <pii, int> > q; memset(vis, false, sizeof vis); vis[cars[car_id].first][cars[car_id].second] = true;
for (q.push(make_pair(make_pair(cars[car_id].first, cars[car_id].second), 0)); !q.empty(); q.pop()) {
pii pos = q.front().first; int step = q.front().second;
for (int i = 0; i < 4; i++) {
int nx = pos.first + dx[i], ny = pos.second + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && matrix[nx][ny] != 'X' && !vis[nx][ny]) {
if (matrix[nx][ny] == 'P') dis[rev[nx][ny]][car_id] = step + 1;
vis[nx][ny] = true;
q.push(make_pair(make_pair(nx, ny), step + 1));
}
}
}
}

Edge *counterpart(Edge *x) {
return edges + ((x - edges) ^ 1);
}

void insert(int u, int v, int c) {
current -> next = first_edge[u];
current -> cap = c;
current -> dest = v;
first_edge[u] = current ++;
}

int dfs(int u, int f) {
if (u == t) return f;
if (vis2[u]) return 0; else vis2[u] = true;
for (Edge *p = first_edge[u]; p; p = p -> next)
if (p -> cap)
if (int res = dfs(p -> dest, min(f, p -> cap))) {
p -> cap -= res;
counterpart(p) -> cap += res;
return res;
}
return 0;
}

bool isok() {
int ans = 0;
while (true) {
memset(vis2, false, sizeof vis2);
if (int res = dfs(s, INF)) ans += res; else break;
}
return ans == cnt_cars; //满流则当前时间足够
}

int make_graph(int limit) { //根据时间上限建图，并返回所选边中容量最大的（只为二分取初值服务）
current = edges; fill(first_edge, first_edge + t + 1, (Edge*)0); int res = INF;
for (int i = 0; i < cnt_cars; i++) {
insert(s, i + 1, 1); insert(i + 1, s, 0);
for (int j = 0; j < cnt_parks; j++)
if (dis[j][i] <= limit) {
insert(i + 1, j + cnt_cars + 1, 1), insert(j + cnt_cars + 1, i + 1, 0);
res = max(res, dis[j][i]);
}
}
for (int i = 0; i < cnt_parks; i++) insert(i + cnt_cars + 1, t, 1), insert(t, i + cnt_cars + 1, 0);
return res;
}

int calc() {
if (!cnt_cars) return 0;
s = 0; t = cnt_cars + cnt_parks + 1;
int  l = 0, r = make_graph(INF - 1); //左开右闭
if (!isok()) return -1;
while (l + 1 < r) {
int mid = l + r >> 1; make_graph(mid);
if (isok()) r = mid; else l = mid;
}
return r;
}

int main(void) {
freopen("2213.in", "r", stdin);
freopen("2213.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%s", matrix[i]);
for (int j = 0; j < m; j++)
if (matrix[i][j] == 'C') cars[cnt_cars++] = make_pair(i, j);
else if (matrix[i][j] == 'P') { rev[i][j] = cnt_parks; parks[cnt_parks++] = make_pair(i, j); }
}
memset(dis, 0x3f, sizeof dis);
for (int i = 0; i < cnt_cars; i++) bfs(i);
//  for (int i = 0; i < cnt_parks; i++) {
//      for (int j = 0; j < cnt_cars; j++) printf("%d ", dis[i][j]);
//      putchar('\n');
//  }
printf("%d\n", calc());
return 0;
}

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120