题意: n*m的矩阵(格子),每个格子上可能有一根柱子,长度0-3(0表示没有),每根柱子上可能会有一只蜥蜴,每只蜥蜴最多跳距离d远;每跳一下柱子的高度就会减1。问最少几只蜥蜴跳不出去。
这题难在建图,想象一下,柱子高度减1用什么办法表示的好。
发现也正是符合网络流的特质的,柱子高度即容量,如果柱子高度为 3,则最多能容纳的流量也就是3,最多允许有3只蜥蜴从这个柱子上经过。
所以可以考虑这样建图:
1)把每个柱子拆成两个点,node1,node2,连一条node1指向node2的边,容量为柱子的高度
2)把在d范围内的每个柱子都连起来,让一根柱子的node2指向另一根的node1,容量为inf,即使得可以相互跳的柱子之间“尾首”相连。
3)加一个源点s,将s与所有有蜥蜴的柱子相连,容量为1
4)加一个汇点t,将所以能直接跳出的柱子的与t相连,容量为inf
最后在这个图上求一下最大流,即是最多能有多少只蜥蜴能跳出去。
【代码】
/* ***********************************************
Author :angon
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define showtime fprintf(stderr,"time = %.15f\n",clock() / (double)CLOCKS_PER_SEC)
#define lld %I64d
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scanl(d) scanf("%I64d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define scannl(n,m) scanf("%I64d%I64d",&n,&m)
#define mst(a,k) memset(a,k,sizeof(a))
#define LL long long
#define N 1005
#define mod 1000000007
inline int read(){int s=0;char ch=getchar();for(; ch<'0'||ch>'9'; ch=getchar());for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0';return s;}
const int MAXN=2200;
const int MAXM=200020;
const int INF=0x3f3f3f3f;
struct Edge
{
int cap,to,next;
}edge[MAXM];
int tol;
int head[MAXN],gap[MAXN],pre[MAXN],dis[MAXN],cur[MAXN];
void init()
{
tol = 0;
mst(head,-1);
}
void addedge(int u,int v,int w,int rw=0)
{
edge[tol].to=v; edge[tol].cap=w; edge[tol].next=head[u]; head[u]=tol++;
edge[tol].to=u; edge[tol].cap=rw; edge[tol].next=head[v]; head[v]=tol++;
}
int sap(int start,int end,int nodenum)
{
mst(dis,0); mst(gap,0);
memcpy(cur,head,sizeof(head));
int u = pre[start] = start, maxflow = 0,aug = -1;
gap[0] = nodenum;
while(dis[start] < nodenum)
{
loop:
for(int &i=cur[u]; ~i;i=edge[i].next)
{
int v = edge[i].to;
if(edge[i].cap && dis[v]+1==dis[u])
{
if(aug==-1 || aug>edge[i].cap)
aug = edge[i].cap;
pre[v] = u;
u = v;
if(v == end)
{
maxflow += aug;
for(u=pre[u] ;v!=start ;v=u,u=pre[u])
{
edge[cur[u]].cap -= aug;
edge[cur[u]^1].cap += aug;
}
aug = -1;
}
goto loop;
}
}
int mindis = nodenum;
for(int i=head[u]; ~i; i=edge[i].next)
{
int v = edge[i].to;
if(edge[i].cap && dis[v] < mindis)
{
cur[u] = i;
mindis = dis[v];
}
}
if((--gap[dis[u]])==0) break;
gap[dis[u]=mindis+1]++;
u = pre[u];
}
return maxflow;
}
char g1[30][30];
char g2[30][30];
int mat[30][30];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T,iCase=1;
scan(T);
while(T--)
{
int n,d;
scann(n,d);
REP(i,0,n) scanf("%s",g1[i]);
int m = strlen(g1[0]);
init();
int node = 0; mst(mat,0);
REP(i,0,n)
REP(j,0,m)
if(g1[i][j] -'0' > 0)
{
mat[i][j] = ++node;
addedge(node*2-1,node*2,g1[i][j]-'0');
}
int s = 0, t = node*2 + 1, nodenum = t+1;
int sum = 0;
REP(i,0,n)
{
scanf("%s",g2[i]);
REP(j,0,m)
if(g2[i][j]=='L')
{
addedge(s,mat[i][j]*2-1,1);
sum++;
}
}
REP(i,0,n)
REP(j,0,m)
if(mat[i][j])
{
REP(ii,0,n)
REPP(jj,0,m)
{
if(i==ii && j==jj) continue;
if(g1[ii][jj]=='0') continue;
if(d>=sqrt((i-ii)*(i-ii)+(j-jj)*(j-jj)))
{
addedge(mat[i][j]*2,mat[ii][jj]*2-1,INF);
}
}
if(i<d||j<d||n-i<=d||m-j<=d)
addedge(mat[i][j]*2,t,INF);
}
int ans = sum - sap(s,t,nodenum);
if(ans==0)
printf("Case #%d: no lizard was left behind.\n",iCase++);
else if(ans==1)
printf("Case #%d: 1 lizard was left behind.\n",iCase++);
else
printf("Case #%d: %d lizards were left behind.\n",iCase++,ans);
}
return 0;
}