[SCOI2007]蜥蜴 (網路流)
阿新 • • 發佈:2020-11-12
剛學習網路流
一上午熟悉\(Dinic\)板子+就調過了這一個題
題目描述
在一個r行c列的網格地圖中有一些高度不同的石柱,一些石柱上站著一些蜥蜴,你的任務是讓儘量多的蜥蜴逃到邊界外。 每行每列中相鄰石柱的距離為1,蜥蜴的跳躍距離是d,即蜥蜴可以跳到平面距離不超過d的任何一個石柱上。石柱都不穩定,每次當蜥蜴跳躍時,所離開的石柱高度減1(如果仍然落在地圖內部,則到達的石柱高度不變),如果該石柱原來高度為1,則蜥蜴離開後消失。以後其他蜥蜴不能落腳。任何時刻不能有兩隻蜥蜴在同一個石柱上。
輸入格式
輸入第一行為三個整數r,c,d,即地圖的規模與最大跳躍距離。以下r行為石竹的初始狀態,0表示沒有石柱,1~3表示石柱的初始高度。以下r行為蜥蜴位置,“L”表示蜥蜴,“.”表示沒有蜥蜴。
輸出格式
輸出僅一行,包含一個整數,即無法逃離的蜥蜴總數的最小值。
樣例
樣例輸入
5 8 2
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........
樣例輸出
1
資料範圍與提示
100%的資料滿足:1<=r, c<=20, 1<=d<=4
Solution
看上去就是每個點有限制能跳過幾只蜥蜴
就相當於邊權中的流量上限
考慮如何建圖
由於對於單個點無法增加邊權
選擇拆點成邊
拆出的點之間的邊權就是流量的限制
首先建立超級源點\(s=0\)
因為圖中有\(n*m\)個點
拆完之後\(2*n*m\)個點
所以超級匯點是\(t=2*n*m+1\)
圖中建邊有四種
- 由源點\(s\)出發,向所有蜥蜴所在的點建立邊權為\(1\)的邊
- 所有有高度(就是蜥蜴可以跳躍的點)拆點,向\((i,j)\)對應的點\((i,j) + n*m\)建邊,邊權為當前點的高度,即流量限制
- 由所有一次能夠跳出矩陣的點向超級匯點\(t\)建邊,邊權無限制,為\(inf\)
- 矩陣內部互相能夠到達的點,邊權無限制,為\(inf\)
最後直接跑\(Dinic\)就行了
注意\(Dinic\)跑出來的是能夠逃離的蜥蜴的數量
要用總數量減一下
Code
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <queue> #include <cmath> #define min(a, b) ({register int AA = a, BB = b; AA < BB ? AA : BB;}) #define inf 10000009 using namespace std; inline int read(){ int x = 0, w = 1; char ch = getchar(); for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; return x * w; } const int ss = 10010; struct node{ int to, nxt, w; }edge[ss * 20]; int head[ss], tot = 1; inline void add(register int u, register int v, register int w){ edge[++tot].to = v; edge[tot].nxt = head[u]; edge[tot].w = w; head[u] = tot; } int dis[ss], cur[ss]; int r, c, d, s, t; bool vis[ss]; queue<int> q; inline bool spfa(register int s){ for(register int i = 0; i <= t; i++) vis[i] = 0, dis[i] = 0x3f3f3f3f, cur[i] = head[i]; dis[s] = 0; q.push(s); while(!q.empty()){ register int u = q.front(); q.pop(); vis[u] = 0; for(register int i = head[u]; i; i = edge[i].nxt){ register int v = edge[i].to; if(dis[v] > dis[u] + 1 && edge[i].w){ dis[v] = dis[u] + 1; if(!vis[v]) q.push(v), vis[v] = 1; } } } return dis[t] != 0x3f3f3f3f; } inline int dfs(register int u, register int flow){ register int res = 0; if(u == t) return flow; for(register int i = cur[u]; i; i = edge[i].nxt){ cur[u] = i; register int v = edge[i].to; if(dis[v] == dis[u] + 1 && edge[i].w){ if(res = dfs(v, min(flow, edge[i].w))){ edge[i].w -= res; edge[i ^ 1].w += res; return res; } } } return 0; } long long ans, cnt; inline long long dinic(){ register long long minflow = 0; while(spfa(s)){ while(minflow = dfs(s, 0x7fffffff)) ans += minflow; } return ans; } inline double getdis(register int a, register int b, register int c, register int d){ return sqrt((a - c) * (a - c) + (b - d) * (b - d)); } inline int change(register int i, register int j){ return (i - 1) * c + j; } int a[25][25], flag[25][25]; char ch[25]; signed main(){ r = read(), c = read(), d = read(); for(register int i = 1; i <= r; i++){ scanf("%s", ch + 1); for(register int j = 1; j <= c; j++) a[i][j] = ch[j] - '0'; } for(register int i = 1; i <= r; i++){ scanf("%s", ch + 1); for(register int j = 1; j <= c; j++) if(ch[j] == 'L') flag[i][j] = 1; } s = 0, t = 2 * c * r + 1; for(register int i = 1; i <= r; i++) for(register int j = 1; j <= c; j++) if(flag[i][j] == 1){ cnt++; add(s, change(i, j), 1); add(change(i, j), s, 0); } for(register int i = 1; i <= r; i++) for(register int j = 1; j <= c; j++) if(a[i][j]){ add(change(i, j), change(i, j) + r * c, a[i][j]); add(change(i, j) + r * c, change(i, j), 0); } for(register int i = 1; i <= r; i++) for(register int j = 1; j <= c; j++){ if(i > d && i <= r - d && j > d && j <= c - d) continue; if(a[i][j]){ add(change(i, j) + r * c, t, inf); add(t, change(i, j) + r * c, 0); } } for(register int i = 1; i <= r; i++){ for(register int j = 1; j <= c; j++){ for(register int p = 1; p <= r; p++){ for(register int q = 1; q <= c; q++){ if(i == p && j == q) continue; if(getdis(i, j, p, q) <= (double)d && a[i][j] && a[p][q]){ add(change(i, j) + r * c, change(p, q), inf); add(change(p, q), change(i, j) + r * c, 0); } } } } } printf("%lld\n", cnt - dinic()); return 0; }