题目链接:点击打开链接
题意:
给定n*m的地图 a个男人 b个女人
下面n*m的方格图.表示空地 *表示障碍。
下面第一行给出中性人的坐标和移动时间
下面a行给出每个男人的坐标和移动时间
下面b行给出女人的坐标和移动时间。
移动时间是指人移动到相邻矩阵的时间(人是不能走到障碍物上的)
每个空地上恰好有一间房子(一间房子只能住一对夫妇,住了人的空地别人还是可以走过的)。
目标:使得所有人都结成夫妇且住在房子里(中性人可以和男的结成夫妇,也可以和女的结成夫妇)
所花的最大时间最小,即最后一个人住进房子的时间最小。
思路:
假设没有变性人,则这题就是一个经典建图了,
二分最大时间,然后建图即可。
设now为每个人允许运动的最大时间
男人连源点 flow = 1
男人连能走到的房子 flow = 1 (所谓能走到就是所花时间<=now)
房子连女人 flow = 1
女人连汇点 flow = 1
因为一个房子只能住一个人,所以房子拆点一下,限流为1
而对于变性人其实并不是任意匹配的,当且仅当 abs(男人数量-女人数量)=1时才能找到解,即一开始就能确定变性人的性别。
f2的话一直wa87,==
#include<iostream> #include<stdio.h> #include<string.h> #include<queue> #include<cmath> template <class T> inline bool rd(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return 0; while (c != '-' && (c<'0' || c>'9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return 1; } template <class T> inline void pt(T x) { if (x <0) { putchar('-'); x = -x; } if (x>9) pt(x / 10); putchar(x % 10 + '0'); } using namespace std; typedef long long ll; const ll inf = 1e10; const int N = 1700; const int M = 10000000; template<class T> struct Max_Flow { int n; int Q[N], sign; int head[N], level[N], cur[N], pre[N]; int nxt[M], pnt[M], E; T cap[M]; void Init(int n) { this->n = n + 1; E = 0; std::fill(head, head + this->n, -1); } //有向rw 就= 0 void add(int from, int to, T c, T rw) { pnt[E] = to; cap[E] = c; nxt[E] = head[from]; head[from] = E++; pnt[E] = from; cap[E] = rw; nxt[E] = head[to]; head[to] = E++; } bool Bfs(int s, int t) { sign = t; std::fill(level, level + n, -1); int *front = Q, *tail = Q; *tail++ = t; level[t] = 0; while (front < tail && level[s] == -1) { int u = *front++; for (int e = head[u]; e != -1; e = nxt[e]) { if (cap[e ^ 1] > 0 && level[pnt[e]] < 0) { level[pnt[e]] = level[u] + 1; *tail++ = pnt[e]; } } } return level[s] != -1; } void Push(int t, T &flow) { T mi = inf; int p = pre[t]; for (int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) { mi = std::min(mi, cap[p]); } for (int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) { cap[p] -= mi; if (!cap[p]) { sign = pnt[p ^ 1]; } cap[p ^ 1] += mi; } flow += mi; } void Dfs(int u, int t, T &flow) { if (u == t) { Push(t, flow); return; } for (int &e = cur[u]; e != -1; e = nxt[e]) { if (cap[e] > 0 && level[u] - 1 == level[pnt[e]]) { pre[pnt[e]] = e; Dfs(pnt[e], t, flow); if (level[sign] > level[u]) { return; } sign = t; } } } T Dinic(int s, int t) { pre[s] = -1; T flow = 0; while (Bfs(s, t)) { std::copy(head, head + n, cur); Dfs(s, t, flow); } return flow; } }; Max_Flow <ll>F; struct node{ int x, y; ll t; node(int a = 0, int b = 0, ll c = 0) :x(a), y(b), t(c){} }AA[N], B[N], C; int n, m, a, b; char mp[24][24]; ll Dis[24][24][24][24]; int has1(int x){ return x - 1; } int has2(int x, int y){ return a + (x - 1)*m + y - 1; } int has3(int x, int y){ return a + n*m + (x - 1)*m + y - 1; } int has4(int x){ return a + 2 * n*m + x - 1; } bool ok(ll now){ int from = has4(b) + 1, to = from + 1; F.Init(to+10); for (int i = 1; i <= a; i++){ F.add(from, has1(i), 1, 0); for (int x = 1; x <= n; x++) for (int y = 1; y <= m; y++) if (Dis[x][y][AA[i].x][AA[i].y] < inf && Dis[x][y][AA[i].x][AA[i].y] * AA[i].t <= now) F.add(has1(i), has2(x, y), 1, 0); } for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)if (mp[i][j] == '.') F.add(has2(i, j), has3(i, j), 1, 0); for (int i = 1; i <= b; i++){ F.add(has4(i), to, 1, 0); for (int x = 1; x <= n; x++) for (int y = 1; y <= m; y++) if (Dis[x][y][B[i].x][B[i].y] < inf && Dis[x][y][B[i].x][B[i].y] * B[i].t <= now) F.add(has3(x, y), has4(i), 1, 0); } return F.Dinic(from, to) == b; } ll solve(){ if (a != b)return -1; ll ans = -1, l = 0, r = 1e18;//二分答案 while (l <= r){ ll mid = (l + r) >> 1; if (ok(mid)){ r = mid - 1; ans = mid; } else l = mid + 1; } return ans; } void pre(){ for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)for (int x = 1; x <= n; x++)for (int y = 1; y <= m; y++)Dis[i][j][x][y] = inf; int step[4][2] = { 0, 1, 0, -1, 1, 0, -1, 0 }; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++){ if (mp[i][j] == '*')continue; Dis[i][j][i][j] = 0; for (int k = 0; k < 4; k++){ int x = i + step[k][0], y = j + step[k][1]; if (1 <= x && x <= n && 1 <= y&&y <= m && mp[x][y] == '.') Dis[i][j][x][y] = 1; } }//Floyd for (int x1 = 1; x1 <= n; x1++)for (int y1 = 1; y1 <= m; y1++) if (mp[x1][y1] == '.') for (int x2 = 1; x2 <= n; x2++)for (int y2 = 1; y2 <= m; y2++) if (mp[x2][y2]=='.' && Dis[x2][y2][x1][y1]<inf) for (int x3 = 1; x3 <= n; x3++)for (int y3 = 1; y3 <= m; y3++) if (mp[x3][y3] == '.') Dis[x2][y2][x3][y3] = min(Dis[x2][y2][x3][y3], Dis[x2][y2][x1][y1] + Dis[x1][y1][x3][y3]); if (a>b)B[++b] = C; //确定变性人的性别,就相当于直接把他看成男(女)人 else AA[++a] = C; } void input(){ rd(n); rd(m); rd(a); rd(b); for (int i = 1; i <= n; i++)scanf("%s", mp[i] + 1); rd(C.x); rd(C.y); rd(C.t); for (int i = 1; i <= a; i++) { rd(AA[i].x); rd(AA[i].y); rd(AA[i].t); } for (int i = 1; i <= b; i++) { rd(B[i].x); rd(B[i].y); rd(B[i].t); } } int main(){ input(); pre(); cout<<solve()<<endl; return 0; } /* 1 1 1 0 . 1 1 1 1 1 1 */
时间: 2024-10-17 21:47:46