题意:给一张n*m的图,#为墙壁,不可达,X为人,@为大门。问所有人到达大门的最短时间。
在任意时间,每个点只能站一个人,大门一次也只能通过一个人。
思路:枚举时间,每个时间建一次图,跑一次最大流,当最大流等于人数时,则该时间即为最短时间。
关于建图,将每个点拆点。设置一个源点S,汇点T。当是点i是X时,S -> i ,流量为1 。
任意时间ti。当点i不是#时,i + ti * n * m-> i' + ti * n * m ,流量是1。当点i是@时,i' +ti* n * m -> T ,流量是1。
对于任意可达的两个点i ,j 连接 i -> j' + ti * n * m ,流量是1。
另外,不可达情况可以对每个X进行BFS,若无法到达输出-1。
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cmath> #include <cstring> #include <queue> #include <set> #include <vector> #include <stack> #include <map> #include <iomanip> #define PI acos(-1.0) #define Max 50005 #define inf 1<<28 #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define REP(i,s,t) for(int i=(s);i<=(t);++i) #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define mp(a,b) make_pair(a,b) #define PII pair<int,int> #define xx first #define yy second using namespace std; inline void readint(int &ret) { char c; do { c = getchar(); } while(c < '0' || c > '9'); ret = c - '0'; while((c=getchar()) >= '0' && c <= '9') ret = ret * 10 + ( c - '0' ); } int n , m ; char Map[20][20] ; int peoplenum = 0 ; struct kdq { int s ,e ,l ,next ; } ed[Max * 100] ; int head[Max] , num ; int S , T ; int mx[5] = {0,1,-1,0,0} ; int my[5] = {0,0,0,1,-1} ; int deep[Max] ; int qe[Max * 100] ; int ans = 0 ; void add(int s ,int e ,int l ) { ed[num].s = s ; ed[num].e = e ; ed[num].l = l ; ed[num].next = head[s] ; head[s] = num ++ ; ed[num].s = e ; ed[num].e = s ; ed[num].l = 0 ; ed[num].next = head[e] ; head[e] = num ++ ; } int inmap(int x ,int y ) { if(x >= 0 && x < n && y >= 0 && y < m && Map[x][y] != '#')return 1 ; return 0 ; } bool bfs(PII s)//对每个X进行BFS,判断其是否可达大门@。 { queue<PII>qe ; qe.push(s) ; bool vis[20][20] ; mem(vis,0) ; vis[s.xx][s.yy] = 1 ; while(!qe.empty()) { PII tt = qe.front() ; qe.pop() ; if(Map[tt.xx][tt.yy] == '@')return 1 ; REP(i,0,4) { PII nextt ; nextt.xx = tt.xx + mx[i] ; nextt.yy = tt.yy + my[i] ; if(inmap(nextt.xx,nextt.yy) && !vis[nextt.xx][nextt.yy]) { vis[nextt.xx][nextt.yy] = 1 ; qe.push(nextt) ; } } } return 0 ; } int dinic_bfs() { mem(deep,-1) ; deep[S] = 0 ; int h = 0 , t = 0 ; qe[h ++ ] = S ; while( h > t ) { int tt = qe[ t ++ ] ; for (int i = head[tt] ; ~i ; i = ed[i].next ) { int e = ed[i].e ; int l = ed[i].l ; if(l > 0 && deep[e] == -1) { deep[e] = deep[tt] + 1 ; qe[h ++ ] = e ; } } } return deep[T] != -1 ; } int dinic_dfs(int now ,int f) { if(now == T)return f ; int flow = 0 ; for (int i = head[now] ;~i ; i = ed[i].next ) { int e = ed[i].e ; int l = ed[i].l ; if(deep[e] == deep[now] + 1 && l > 0 && (f - flow ) > 0 ) { int mm = min(l,f - flow) ; int nn = dinic_dfs(e,mm) ; flow += nn ; ed[i].l -= nn ; ed[i ^ 1].l += nn ; } } if(flow == 0)deep[now] = -2 ; return flow ; } int dinic() { int flow = 0 ; while(dinic_bfs()) { flow += dinic_dfs(S,inf) ; } return flow ; } bool check() { REP(i,0,n - 1) { REP(j,0,m - 1) { if(Map[i][j] == 'X') if(!bfs(mp(i,j)))return 0 ; } } return 1 ; } void build(int ceng)//对每个时间段进行建图。 { REP(i,0,n - 1 ) REP(j,0,m - 1) { if(Map[i][j] == '#')continue ; add(i * m + j + 1 + (ceng - 1) * n * m , i * m + j + 1 + n * m + (ceng - 1) * n * m , 1) ;//i + ti * n * m -> i' + ti * n * m REP(k,0,4) { int tx = i + mx[k] ; int ty = j + my[k] ; if(inmap(tx,ty))add(i * m + j + 1 + (ceng - 1) * n * m ,tx * m + ty + 1 + n * m + (ceng - 1) * n * m ,1) ;//两点可达, i + ti * n * m -> j' + ti * n * m } if(Map[i][j] == '@')add(i * m + j + 1 + n * m + (ceng - 1) * n * m , T , 1) ;//若为大门 i' + ti * n * m-> T } } int solve(int ceng) { build(ceng) ; ans += dinic() ; if(ans >= peoplenum)return 1 ; return 0 ; } void init() { mem(head,-1) ; num = 0 ; ans = 0 ; peoplenum = 0 ; } int main() { while(scanf("%d%d",&n,&m) != EOF) { init() ; S = 0 , T = 50000 ; REP(i,0,n - 1){ scanf("%s",Map[i]) ; REP(j,0,m - 1) if(Map[i][j] == 'X'){ peoplenum ++ ; add(S,i * m + j + 1 ,1) ; } } if(!peoplenum || !check())puts("-1") ; else { int ce = 1 ; while(1) { if(solve(ce))break ; ce ++ ; } printf("%d\n",ce) ; } } return 0; }