[HNOI2007]紧急疏散EVACUATE

嘟嘟嘟

 

看数据范围,第一反应觉得爆搜是不是能骗点分,但发现爆搜太难写了,于是就开始想想正解……

正解大概猜到了是网络流,但是怎么把时间这个条件加入到图的内容中,却困扰了我好半天,总是感觉把这种不同维度的条件整合到一块肯定得用什么很奇葩的方法,于是我就想不出来了……

看题解。

先二分时间(有道理啊,我怎么没想出来)。

然后我们可以转化一下,每一个人都已经到达了门前,不过到达的时刻不同,也就是说,对于这个人和这扇门他只能在大于等于他的到达时间的时候进去。

题中还说,一扇门一秒只能进一个人,为了把这个限制条件体现出来,我们把每一扇门拆点:对于当前二分的值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 }
View Code

 

posted @ 2018-09-26 08:43  mrclr  阅读(277)  评论(0编辑  收藏  举报