[SMOJ2213]停车场
来源:互联网 发布:牛股宝软件下载 编辑:程序博客网 时间:2024/04/20 18:06
首先要发现数据范围是比较小,如果是传统的图论题,一般不会只有这么小。而再联想最近所做的二分图匹配,似乎有些吻合。当然,仅凭这个无法作出判断。
刚读题的时候,我还以为是搜索题。但是仔细分析一下,很多条件和限制都说明无法直接用搜索解决。
最明显的一点,直接搜索无法处理:每辆车可以停进若干停车位,每个车位只能停一辆车。而要求的是一种分配的方案,使所有车中最大的移动时间最小。
看到最小化最大值,自然而然就应该要想到二分。很遗憾的是,比赛的时候,我做到这里所剩的时间已经不多了,也没有用心发掘题目的本质,以致错失正解。
最终要求的是花费时间,那么不妨就二分这个值。显然,假设当前要考虑花费
则现在问题的关键转化为:如何判断所有车能否在
首先明确一点,每辆车到各个停车场的距离可以预先算出,因为各辆车的开车过程(只要最终不停在一起)是不会相互影响的,允许多台汽车同时进入某个可通行格子。所以,以每辆车为起点各跑 bfs 即可,数据范围也比较小,这一步不会占用太多时间。
现在回到我们的问题。可以认为,“停车”就是将车与停车场进行匹配的过程,车到一个停车场的距离为
但是,在网络中构图的时候,只需把这些有效边连接的点之间连一条容量为 1 的边即可。换言之,只要在限定时间内能够到达,具体的值,我们并不关心。
这样,就可以把能够在
需要注意的是对特殊情况的判断。当没有车的时候,相当于所有移动已经完成,则应该输出 0。
参考代码:
#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;}
- [SMOJ2213]停车场
- 停车场
- 停车场
- 停车场
- 停车场
- 停车场
- 停车场
- 停车场
- 停车场
- 停车场收费
- 停车场~c++
- 停车场问题
- 停车场程序设计
- 停车场管理
- 停车场模拟
- 停车场模拟
- 停车场模拟
- 停车场模拟
- Python使用 time和datetime模块随意操作 时间
- Javascript 深入研究
- 使用web3.js编译Solidity之遇到的问题
- 3.Redis的数据结构
- 在不同的电脑环境有时无法访问mysql数据库
- [SMOJ2213]停车场
- springMVC 注解 @Autowired和@Resource 的关系
- 设计模式-建造者模式
- C++11 线程 锁 小例子
- 关于跨域,以及跨域的几种方式
- 扩展的放音标签
- 量化工具介绍
- Linux Directory Structure
- vue-cli 快速构建项目