标签:turn imp scanf pac 输出 continue bfs 个人 nbsp
题目大意:
在一个n*m的房间中 ‘X’为墙 ‘D’为门 ‘.’为人
门只存在与外围 人每秒钟只能向四连通区域走一步
门比较狭窄 每秒钟只能通过一个人
求所有人逃脱的最短时间 如果不可能则输出impossible
对每个门 广搜出能在这个门逃脱的人的逃出时间
将 对应各个时间的这个门 当做不同的点
即 若有d个门 p个人
时间1对应的门编号为 0~d-1
时间2对应的门编号为 d~2*d-1
时间t对应的门编号为 (t-1)*d~t*d-1
然后将人编号为 t*d~t*d+p-1
再将 对应时间的门的编号 与 对应时间在该门逃脱的人 连边
而一个人若能在 t 时间逃脱 那么同样可以在 t+1、t+2、t+3...时间逃脱
所以 对应时间到最晚时间的该门的编号 都可与 这个人连边
这样找到 各个时间的门 与 人 的最大匹配
时间从小到大 这样判断到最大匹配数恰好等于人数时说明此时所有人都可逃脱
#include <bits/stdc++.h> using namespace std; int n,m; char G[15][15]; int mov[4][2]={0,1,1,0,0,-1,-1,0}; int dis[15][15][15][15]; // dis[x][y][i][j] 门的位置为xy 人的位置为ij 保存逃脱的最短用时 struct NODE { int x,y; }; vector <NODE> D, P; // D记录门的位置 P记录人的位置 const int E=12*12*12*15; vector <int> e[E]; // 邻接表 bool bound(int x1,int y1) { return x1<0 || x1>=n || y1<0 || y1>=m; } void bfs(int x1,int y1,int d[15][15]) { // d为dis[x1][y1]对应的后两维 queue <NODE> q; q.push((NODE){x1,y1}); d[x1][y1]=0; while(!q.empty()) { NODE e=q.front(); q.pop(); for(int i=0;i<4;i++) { int x2=e.x+mov[i][0], y2=e.y+mov[i][1]; if(bound(x2,y2) || d[x2][y2]!=-1) continue; if(G[x2][y2]!=‘.‘) continue; d[x2][y2]=d[e.x][e.y]+1; q.push((NODE){x2,y2}); } } } /**二分图最大匹配*/ bool vis[E]; int mat[E]; bool dfs(int u) { vis[u]=1; for(int i=0;i<e[u].size();i++) { int v=e[u][i], d=mat[v]; if(d==-1 || !vis[d]&&dfs(d)) { mat[u]=v, mat[v]=u; return 1; } } return 0; } int match(int d,int p) { int res=0; memset(mat,-1,sizeof(mat)); for(int i=0;i<n*d;i++) // 时间从小到大 一旦找到最大匹配就是最快逃脱时间 if(mat[i]==-1) { memset(vis,0,sizeof(vis)); if(dfs(i)) { res++; if(res==p) return i/d+1; /// 一旦匹配数等于人数 说明此时所有人都已匹配 } } return 0; } /***/ void solve() { memset(dis,-1,sizeof(dis)); D.clear(), P.clear(); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) if(G[i][j]==‘D‘) { D.push_back((NODE){i,j}); bfs(i,j,dis[i][j]);// 广搜出所有能到ij门的人的最短时间 } else if(G[i][j]==‘.‘) P.push_back((NODE){i,j}); } n*=m; for(int i=0;i<E;i++) e[i].clear(); int d=D.size(), p=P.size(); for(int i=0;i<d;i++) { for(int j=0;j<p;j++) { int t=dis[D[i].x][D[i].y][P[j].x][P[j].y]; if(t!=-1) { // 说明最快t时间可以逃脱 for(int k=t;k<=n;k++) // 则t以上时间都可逃脱 连边 e[(k-1)*d+i].push_back(n*d+j); } } } if(p==0) { printf("0\n"); return; } int ans=match(d,p); if(ans) printf("%d\n",ans); else printf("impossible\n"); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%s",G[i]); solve(); } return 0; }
标签:turn imp scanf pac 输出 continue bfs 个人 nbsp
原文地址:https://www.cnblogs.com/zquzjx/p/10121424.html