题意:
摘自:https://www.cnblogs.com/DOLFAMINGO/p/8144939.html
在一个n*m的地图上, 有一些高度不一柱子, 又有一些青蛙站在柱子上,且一根柱子最多只能站一只青蛙。青蛙一次最多可跳跃d个距离,即:abs(x-xx)+abs(y-yy)<=d,且每跳一次,青蛙原来站着的柱子的高度会下降一个单位,当柱子的高度为0时,就无效了。当青蛙跳出界时,才算安全,问:最少有多少个青蛙不能跳出地图?
思路:
最大流。柱子的高度就是其容量。将柱子拆点。
源点到有蜥蜴的柱子连一条边,容量为1。
柱子之间(走d距离可达)连一条边,容量为INF.
能一步走出去的柱子到T连一条边,容量为INF
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 400+5;
using namespace std;
char map1[25][25], map2[25][25];
int Id[25][25];
// 图
struct Edge{
int v, cap, flow, next;
};
Edge edges[200000];
int head[maxn*2], cnt;
int dis[maxn*2]; // 分层的编号
int cur[maxn*2]; // 当前弧,重要优化!!!
void init(){
cnt = 0;
memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int cap){
edges[cnt].v = v; edges[cnt].cap = cap; edges[cnt].flow = 0;
edges[cnt].next = head[u]; head[u] = cnt++;
// 反向弧
edges[cnt].v = u; edges[cnt].cap = 0; edges[cnt].flow = 0;
edges[cnt].next = head[v]; head[v] = cnt++;
}
// 分层
int Q[maxn*4]; // 模拟队列
bool bfs(int s, int t){
memset(dis, -1, sizeof(dis));
dis[s] = 0;
int front = 0, rear = 0;
Q[rear++] = s;
while(front < rear){
int x = Q[front++];
if(x == t) return true;
for(int i = head[x]; i != -1; i = edges[i].next){
Edge& e = edges[i];
if(dis[e.v] == -1&&e.cap > e.flow){
dis[e.v] = dis[x] + 1;
Q[rear++] = e.v;
}
}
}
return dis[t] != -1;
}
int dfs(int s, int t, int cur_flow){
if(s == t||cur_flow == 0) return cur_flow;
int ans = 0;
for(int& i = cur[s]; i != -1; i = edges[i].next){
int c = i;
Edge e = edges[c];
if(dis[e.v] == dis[s] + 1&&e.cap > e.flow){
int a2 = min(cur_flow, e.cap-e.flow);
int w = dfs(e.v, t, a2);
edges[c].flow += w;
edges[c^1].flow -= w;
cur_flow -= w;
ans += w;
if(cur_flow <= 0) break;
}
}
return ans;
}
// 最大流
int Dinic(int s, int t){
int ans = 0;
while(bfs(s,t)){
memcpy(cur, head, sizeof(head));
ans += dfs(s,t,INF);
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
int T; scanf("%d",&T);
int n,m,d;
int kase = 1;
while(T--){
init();
scanf("%d%d",&n,&d);
for(int i = 1; i <= n; ++i) scanf("%s",map1[i]+1);
for(int i = 1; i <= n; ++i) scanf("%s",map2[i]+1);
//printf("kk\n");
m = strlen(map1[1]+1); //printf("m = %d\n",m);
int tot = 1, lizard = 0;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j){
if(map2[i][j] == 'L') ++lizard;
if(map1[i][j] > '0') Id[i][j] = tot++;
}
//printf("lizard = %d\n",lizard);
--tot;
int s = 0, t = 2*tot+1;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j){
if(map2[i][j] == 'L') addEdge(s, Id[i][j], 1);
int cap = map1[i][j] - '0';
if(cap > 0&&(i-d < 1||i+d > n||j-d < 1||j+d > m)) addEdge(Id[i][j]+tot, t, INF);
if(cap > 0){
addEdge(Id[i][j], Id[i][j]+tot, cap);
for(int p = -d; p <= d; ++p)
for(int q = abs(p) - d; q <= d - abs(p); ++q){
int tx = i + p, ty = j + q;
if(tx < 1||tx > n||ty < 1||ty > m) continue;
if(map1[tx][ty] > '0') addEdge(Id[i][j]+tot, Id[tx][ty], INF);
}
}
}
int ans = lizard - Dinic(s,t);
if(ans == 0) printf("Case #%d: no lizard was left behind.\n", kase++);
else if(ans == 1) printf("Case #%d: 1 lizard was left behind.\n", kase++);
else printf("Case #%d: %d lizards were left behind.\n", kase++, ans);
}
fclose(stdin);
return 0;
}