这题主要考网络流建图。
首先每一只蜥蜴像自己所在的石柱连边,然后如果这一只蜥蜴像能跳到的所有石柱连边,那就错了。因为每一只蜥蜴能跳到别的石柱上,然后再跳到更远的石柱上,而上述连边的意思是蜥蜴只能跳到他一步能达到的石柱上。所以,正确的连边应该是以每一个石柱,向能到达的石柱连边,容量为INF。
题中还有一点:每离开一个石柱,石柱高度减一,这相当于限制了每一个石柱能承受的蜥蜴数量。那么一个常见的做法就是拆点:将每一个石柱拆成跳到他,和从他跳走的,然后连一条容量为石柱高度的边。
最后就是对于每一个能从他跳出边界的石柱,从他跳走的点向汇点连一条INF的边。
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 = 1205; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 27 if(last == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar('-'); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int n, m, t, d, tot = 0; 38 39 struct Edge 40 { 41 int from, to, cap, flow; 42 }; 43 vector<Edge> edges; 44 vector<int> G[maxn]; 45 void addEdge(int from, int to, int w) 46 { 47 edges.push_back((Edge){from, to, w, 0}); 48 edges.push_back((Edge){to, from, 0, 0}); 49 int sz = edges.size(); 50 G[from].push_back(sz - 2); 51 G[to].push_back(sz - 1); 52 } 53 54 int dx[20], dy[20], st = 0; 55 void init(int x) 56 { 57 for(int i = -d; i <= d; ++i) 58 for(int j = -d; j <= d; ++j) 59 if(i * i + j * j <= d * d) dx[++st] = i, dy[st] = j; 60 } 61 62 int getnum(int x, int y) 63 { 64 return m * (x - 1) + y; 65 } 66 67 bool judge(int x, int y) 68 { 69 if(x + d > n || x - d <= 0 || y + d > m || y - d <= 0) return 1; 70 return 0; 71 } 72 73 void add(int x, int y) 74 { 75 int u = getnum(x, y) + n * m; 76 for(int i = 1; i <= st; ++i) 77 { 78 int newx = x + dx[i], newy = y + dy[i]; 79 if(newx > 0 && newx <= n && newy > 0 && newy <= m) 80 addEdge(u, getnum(newx, newy), INF); 81 } 82 83 } 84 85 int dis[maxn]; 86 bool bfs() 87 { 88 Mem(dis, 0); dis[0] = 1; 89 queue<int> q; q.push(0); 90 while(!q.empty()) 91 { 92 int now = q.front(); q.pop(); 93 for(int i = 0; i < (int)G[now].size(); ++i) 94 { 95 Edge& e = edges[G[now][i]]; 96 if(!dis[e.to] && e.cap > e.flow) 97 { 98 dis[e.to] = dis[now] + 1; 99 q.push(e.to); 100 } 101 } 102 } 103 return dis[t]; 104 } 105 int cur[maxn]; 106 int dfs(int now, int res) 107 { 108 if(now == t || res == 0) return res; 109 int flow = 0, f; 110 for(int& i = cur[now]; i < (int)G[now].size(); ++i) 111 { 112 Edge& e = edges[G[now][i]]; 113 if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(res, e.cap - e.flow))) > 0) 114 { 115 e.flow += f; 116 edges[G[now][i] ^ 1].flow -= f; 117 flow += f; 118 res -= f; 119 if(res == 0) break; 120 } 121 } 122 return flow; 123 } 124 125 int maxflow() 126 { 127 int flow = 0; 128 while(bfs()) 129 { 130 Mem(cur, 0); 131 flow += dfs(0, INF); 132 } 133 return flow; 134 } 135 136 char c[25]; 137 138 int main() 139 { 140 n = read(); m = read(); d = read(); 141 init(d); 142 t = n * m * 3 + 1; 143 for(int i = 1; i <= n; ++i) 144 for(int j = 1; j <= m; ++j) 145 { 146 int x; scanf("%1d", &x); 147 if(x) 148 { 149 int u = getnum(i, j); 150 addEdge(u, n * m + u, x); 151 if(judge(i, j)) addEdge(n * m + u, t, INF); 152 add(i, j); 153 } 154 } 155 for(int i = 1; i <= n; ++i) 156 { 157 scanf("%s", c + 1); 158 for(int j = 1; j <= m; ++j) 159 if(c[j] == 'L') 160 { 161 tot++; 162 int u = getnum(i, j) + ((n * m) << 1); 163 addEdge(0, u, 1); 164 addEdge(u, getnum(i, j), 1); 165 } 166 } 167 write(tot - maxflow()); enter; 168 return 0; 169 }