看数据范围,第一反应觉得爆搜是不是能骗点分,但发现爆搜太难写了,于是就开始想想正解……
正解大概猜到了是网络流,但是怎么把时间这个条件加入到图的内容中,却困扰了我好半天,总是感觉把这种不同维度的条件整合到一块肯定得用什么很奇葩的方法,于是我就想不出来了……
看题解。
先二分时间(有道理啊,我怎么没想出来)。
然后我们可以转化一下,每一个人都已经到达了门前,不过到达的时刻不同,也就是说,对于这个人和这扇门他只能在大于等于他的到达时间的时候进去。
题中还说,一扇门一秒只能进一个人,为了把这个限制条件体现出来,我们把每一扇门拆点:对于当前二分的值mid,把每一扇门拆成mid + 1(包括0这个时刻)个点,每一个点向汇点连一条容量为1的边,然后对于一个人在哪个时候到达这个门的,就像第几时刻的点连一条容量为1的边。
还有一点,就是如果第 i 时刻人数大于1的话,那自然的剩下的人要等到 j (j > i)的时刻才能进门,为了体现这个,我们还要把每一扇门的每一个拆点 i,向 i +1连一条容量为INF的边。
建图到这里就讲完了,接下来说一下预处理。
首先我们要预处理每一个人到每一扇门的距离,而不是只到最近的门,因为虽然最近,但可能等待的时间非常长。我们可以从每一扇门开始对这个图来一次bfs,记录每一个点到这扇门的距离(我存到了一个vector中)。
然后二分重新建图的时候对于每一个点,从源点连一条容量为1的边;对于每一扇门,先按时间拆点,然后遍历自己的vector连边就行可以了。
还有一个值得注意的就是点的编号别重了,而且要确定好汇点的编号是多大:理论上最大值应该是20 * 20 + 76 * 20 * 20 = 30800, 76是最多有76扇门,但实际上我们只用开1e4就能过了。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 1e4 + 5; 21 const int max_map = 405; 22 inline ll read() 23 { 24 ll ans = 0; 25 char ch = getchar(), last = ' '; 26 while(!isdigit(ch)) {last = ch; ch = getchar();} 27 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 28 if(last == '-') ans = -ans; 29 return ans; 30 } 31 inline void write(ll x) 32 { 33 if(x < 0) x = -x, putchar('-'); 34 if(x >= 10) write(x / 10); 35 putchar(x % 10 + '0'); 36 } 37 38 int n, m, t, tot1 = 0, tot2 = 0; 39 char a[25][25]; 40 41 int getnum(int x, int y) 42 { 43 return (x - 1) * m + y; 44 } 45 46 #define pr pair<int, int> 47 #define mp make_pair 48 vector<pr> E[max_map]; 49 struct Node 50 { 51 int x, y, dis; 52 }; 53 const int dx[5] = {-1, 0, 1, 0}, dy[5] = {0, 1, 0, -1}; 54 bool vis[25][25]; 55 void bfs1(int x, int y) 56 { 57 Mem(vis, 0); 58 int u = getnum(x, y); 59 queue<Node> q; q.push((Node){x, y, 0}); 60 vis[x][y] = 1; 61 while(!q.empty()) 62 { 63 int x = q.front().x, y = q.front().y, Dis = q.front().dis; 64 q.pop(); 65 for(int i = 0; i < 4; ++i) 66 { 67 int newx = x + dx[i], newy = y + dy[i]; 68 if(newx > 0 && newx <= n && newy > 0 && newy <= m && a[newx][newy] == '.' && !vis[newx][newy]) 69 { 70 E[u].push_back(mp(getnum(newx, newy), Dis + 1)); 71 vis[newx][newy] = 1; 72 q.push((Node){newx, newy, Dis + 1}); 73 } 74 } 75 } 76 77 } 78 79 void init() 80 { 81 for(int i = 1; i <= n; ++i) 82 for(int j = 1; j <= m; ++j) 83 { 84 if(a[i][j] == '.') tot1++; 85 if(a[i][j] == 'D') tot2++, bfs1(i, j); 86 } 87 } 88 89 struct Edge 90 { 91 int from, to, cap, flow; 92 }; 93 vector<Edge> edges; 94 vector<int> G[maxn]; 95 void addEdge(int from, int to, int w) 96 { 97 edges.push_back((Edge){from, to, w, 0}); 98 edges.push_back((Edge){to, from, 0, 0}); 99 int sz = edges.size(); 100 G[from].push_back(sz - 2); 101 G[to].push_back(sz - 1); 102 } 103 104 void build_Gra(int x) 105 { 106 edges.clear(); 107 for(int i = 0; i <= t; ++i) G[i].clear(); 108 int cnt = 0; 109 for(int i = 1; i <= n; ++i) 110 for(int j = 1; j <= m; ++j) 111 { 112 if(a[i][j] == '.') addEdge(0, getnum(i, j), 1); 113 if(a[i][j] == 'D') 114 { 115 int u = getnum(i, j); 116 int tp = n * m + cnt * x; 117 for(int k = 1; k <= x; ++k) addEdge(tp + k, t, 1); 118 for(int k = 1; k < x; ++k) addEdge(tp + k, tp + k + 1, INF); 119 for(int k = 0; k < (int)E[u].size(); ++k) 120 { 121 int nod = E[u][k].first, d = E[u][k].second; 122 if(d <= x) addEdge(nod, tp + d, 1); 123 } 124 cnt++; 125 } 126 } 127 } 128 129 int dis[maxn]; 130 bool bfs() 131 { 132 Mem(dis, 0); dis[0] = 1; 133 queue<int> q; q.push(0); 134 while(!q.empty()) 135 { 136 int now = q.front(); q.pop(); 137 for(int i = 0; i < (int)G[now].size(); ++i) 138 { 139 Edge& e = edges[G[now][i]]; 140 if(!dis[e.to] && e.cap > e.flow) 141 { 142 dis[e.to] = dis[now] + 1; 143 q.push(e.to); 144 } 145 } 146 } 147 return dis[t]; 148 } 149 int cur[maxn]; 150 int dfs(int now, int res) 151 { 152 if(now == t || res == 0) return res; 153 int flow = 0, f; 154 for(int& i = cur[now]; i < (int)G[now].size(); ++i) 155 { 156 Edge& e = edges[G[now][i]]; 157 if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(res, e.cap - e.flow))) > 0) 158 { 159 e.flow += f; 160 edges[G[now][i] ^ 1].flow -= f; 161 flow += f; res -= f; 162 if(res == 0) break; 163 } 164 } 165 return flow; 166 } 167 168 int maxflow() 169 { 170 int flow = 0; 171 while(bfs()) 172 { 173 Mem(cur, 0); 174 flow += dfs(0, INF); 175 } 176 return flow; 177 } 178 179 int main() 180 { 181 n = read(); m = read(); 182 for(int i = 1; i <= n; ++i) scanf("%s", a[i] + 1); 183 init(); 184 t = n * m * (tot2 + 1) + 1; 185 int L = 0, R = n * m + 1; 186 while(L < R) 187 { 188 int mid = (L + R) >> 1; 189 build_Gra(mid); 190 if(maxflow() >= tot1) R = mid; 191 else L = mid + 1; 192 } 193 if(L > n * m) printf("impossible\n"); 194 else write(L), enter; 195 return 0; 196 }