题目
https://codeforces.com/gym/103427/problem/D
大意:给一个 a*b 的地图,有 n 个人和 n 个出口。出口只能用一次,人到了出口可以选择不出去。每次人可以LRUDS(不动)P(在出口或已经出去了才有这个,代表出去)五种操作(都是瞬移)。每个时刻每个位置只能有一个人。问 n 个人全出去的最少时间以及给出一种方案。
思路
这是官方题解 https://www.zhihu.com/question/500358591/answer/2239217951
注意数据都是100级别的。
首先,肯定有解,且不大于 a*b。因为可以把地图按贪吃蛇那样展开成一条线,然后一次分配出口即可。
那么,就可以先二分答案 t,再建造一个 t 层的图跑网络流。
如图,是个 t=3 的情形
每层有两组,上面那组每对点代表一个格子,下面那组每对点代表一个出口。之所以每层的点要成对出现,是为了各自在他们之间连上一条边权1的边来限制住流量。
跑完网络流,每条流量代表一个人的路径。最终流量刚好为 n 则代表可以成功。
时间复杂度是二分乘上网络流。
代码
// https://codeforces.com/gym/103427/problem/D
#include <bits/stdc++.h>
using namespace std;
template <typename Cap = int64_t>
class Dinic{
private:
struct E{
int to, rev;
Cap cap;
char ch;
};
int n, st, ed;
vector<vector<E>> G;
vector<int> lv, idx;
vector<pair<int, int>> egs;
bool BFS(){
lv.assign(n, -1);
queue<int> bfs;
bfs.push(st); lv[st] = 0;
while (not bfs.empty()){
int u = bfs.front(); bfs.pop();
for (auto e: G[u]) {
if (e.cap <= 0 or lv[e.to]!=-1) continue;
bfs.push(e.to); lv[e.to] = lv[u] + 1;
}
}
return lv[ed] != -1;
}
Cap DFS(int u, Cap f){
if (u == ed) return f;
Cap ret = 0;
for(int &i = idx[u]; i < int(G[u].size()); ++i) {
auto &e = G[u][i];
if (e.cap <= 0 or lv[e.to]!=lv[u]+1) continue;
Cap nf = DFS(e.to, min(f, e.cap));
ret += nf; e.cap -= nf; f -= nf;
G[e.to][e.rev].cap += nf;
if (f == 0) return ret;
}
if (ret == 0) lv[u] = -1;
return ret;
}
public:
void init(int n_) { G.assign(n = n_, vector<E>()); egs.clear(); }
void addEdge(int u, int v, Cap c, char ch){
G[u].push_back({v, int(G[v].size()), c, ch});
G[v].push_back({u, int(G[u].size())-1, 0, ch});
egs.emplace_back(v, int(G[v].size()) - 1);
}
Cap maxFlow(int st_, int ed_){
st = st_, ed = ed_; Cap ret = 0;
while (BFS()) {
idx.assign(n, 0);
Cap f = DFS(st, numeric_limits<Cap>::max());
ret += f;
if (f == 0) break;
}
return ret;
}
Cap flow_at(int eid) const {
return G[egs[eid].first][egs[eid].second].cap;
}
// 输出答案
void printAns(int Ha, int AB, int b, int t)
{
for (int i=0; i<int(G[st].size()); i++) {
int cur=G[st][i].to;
int lst=ed;
int x,y,xx,yy;
x=xx=(cur-1)%Ha/2/b;
y=yy=(cur-1)%Ha/2%b+1;
string str;
while (cur!=ed) {
for (int j=0; j<int(G[cur].size()); j++) {
E &e=G[cur][j];
if (!e.cap && e.to!=lst && (e.to-1)/Ha>=(cur-1)/Ha) {
if (e.ch>='A' && e.ch<='Z') str+=e.ch;
//printf("%c",Ech[h]);
lst=cur;
cur=e.to;
if (cur%Ha<=AB && (cur%2==0) && cur!=ed) {
xx=(cur-1)%Ha/2/b;
yy=(cur-1)%Ha/2%b+1;
}
break;
}
}
}
str.pop_back();
printf("%d %d %d %d %s\n",x,y,xx,yy,str.c_str());
}
}
};
int n,a,b;
int S,T;
int SUM,AB;
int sx[200],sy[200],ex[200],ey[200];
int fx[4][2]={{-1,0}, {1,0}, {0,-1}, {0,1}};
char ch[4]={'U','D','L','R'};
Dinic<int> DDD;
int trans_s2m(int x, int y, int t) {return (x*b+y)*2+SUM*t;}
int trans_e2m(int x, int t) {return x*2+AB+SUM*t;}
bool check(int ttt)
{
S=0;
T=(ttt+1)*SUM;
DDD.init(T+10);
for (int i=1; i<=n; i++) {
DDD.addEdge(S, trans_s2m(sx[i], sy[i], 0), 1, '.');
}
for (int t=0; t<ttt; t++) {
for (int i=1; i<=a; i++)
for (int j=1; j<=b; j++) {
DDD.addEdge(trans_s2m(i,j,t), trans_s2m(i,j,t)+1, 1, '-');
DDD.addEdge(trans_s2m(i,j,t)+1, trans_s2m(i,j,t+1), 1, 'S');
for (int ff=0,ii,jj; ff<4; ff++) {
ii=i+fx[ff][0], jj=j+fx[ff][1];
if (ii<=0 || ii>a || jj<=0 || jj>b) continue;
DDD.addEdge(trans_s2m(i,j,t)+1, trans_s2m(ii,jj,t+1), 1, ch[ff]);
}
for (int k=1; k<=n; k++) {
DDD.addEdge(trans_e2m(k,t), trans_e2m(k,t)+1, 1, '-');
DDD.addEdge(trans_e2m(k,t)+1, trans_e2m(k,t+1), 1, 'P');
DDD.addEdge(trans_s2m(ex[k],ey[k],t)+1, trans_e2m(k,t+1), 1, 'P');
}
}
}
for (int i=1; i<=n; i++) {
DDD.addEdge(trans_e2m(i,ttt), T, 1, '!');
}
int mxflow = DDD.maxFlow(S, T);
return mxflow==n;
}
void solve()
{
scanf("%d%d%d",&n,&a,&b);
AB=(a+1)*b*2;
SUM=AB+n*2+2;
vector<int> s(n+1);
for (int i=1; i<=n; i++) {
scanf("%d%d",&sx[i],&sy[i]);
}
for (int i=1; i<=n; i++) {
scanf("%d%d", &ex[i], &ey[i]);
}
int ans=a*b;
int L=0, R=a*b;
while (L<=R) {
int M=(L+R)>>1;
if (check(M)) {
ans=M;
R=M-1;
}
else {
L=M+1;
}
}
check(ans);
printf("%d\n",ans-1);
DDD.printAns(SUM, AB, b, ans-1);
}
int main()
{
solve();
return 0;
}
/*
// 3 4 4 1 1 1 4 4 4 1 3 2 3 2 4
// 3 2 2 1 1 1 2 2 2 1 1 2 1 2 2
// 2 3 3 1 1 1 3 1 2 2 2
10 1 100 1 17 1 49 1 12 1 37 1 83 1 44 1 75 1 78 1 72 1 3 1 75 1 47 1 55 1 81 1 6 1 59 1 17 1 68 1 28 1 24
10 1 100
1 17
1 49
1 12
1 37
1 83
1 44
1 75
1 78
1 72
1 3
1 75
1 47
1 55
1 81
1 6
1 59
1 17
1 68
1 28
1 24
*/