这题是网络流最大流。
难点在于拆点。因为石柱会不断缩水,所以将石柱拆成两个点,连一条流量为石柱高度的边。再将源点S与有蜥蜴的点连一条流量为1的边(每点只有一只蟋蟀),所有互相可以到达的点连∞的边,然后将可以跳到外面的点与汇点T连∞的边。跑最大流即可。
放一下代码,好渣的速度(>﹏<)
/**************************************************************
Problem: 1066
User: fantasticwtl
Language: C++
Result: Accepted
Time:472 ms
Memory:4744 kb
****************************************************************/
#include <cstdio>
#include <cmath>
#include <memory.h>
#include <algorithm>
using namespace std;
int a[21][21],d[1001],g[1001][1001],q[1001],n,m,cn,k,tot[21][21],ans,kk;
char c,enter;
void make(int x,int y)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(sqrt((i-x)*(i-x)+(j-y)*(j-y))<=k&&(i!=x||j!=y))g[tot[x][y]+1][tot[i][j]]=10000000;//所有互相可以到达的点连∞的边
if(x<=k||x>=n-k+1||y<=k||y>=m-k+1)g[tot[x][y]+1][cn]=10000000;//可以跳到外面的点与汇点T连∞的边
}
bool jz ()
{
memset(d,0,sizeof(d));
d[1]=1;q[1]=1;
int h=0,t=1;
while(h<t){
h++;
for(int i=1;i<=cn;i++)
if(d[i]==0&&g[q[h]][i]){
t++;d[i]=d[q[h]]+1;q[t]=i;
}
if(d[cn])return 1;
}
if(d[cn]==0)return 0;else return 1;
}
int find (int x,int y)
{
if(x>=cn)return y;
int a=0;
for(int i=1;i<=cn;i++)
if(d[i]==d[x]+1&&g[x][i]>0&&(a=find(i,min(y,g[x][i])))){g[x][i]-=a;g[i][x]+=a;return a;}
return 0;
}
int main ()
{
scanf("%d%d%d",&n,&m,&k);
cn=1;
for(int i=1;i<=n;i++){
scanf("%c",&enter);
for(int j=1;j<=m;j++){
scanf("%c",&c);
if(c>'0'){
a[i][j]=c-48;
cn++;
tot[i][j]=cn;
cn++;
}
}
}
cn++;
for(int i=1;i<=n;i++){
scanf("%c",&enter);
for(int j=1;j<=m;j++){
scanf("%c",&c);
if(c=='L'){
ans=ans+1;
kk=tot[i][j];
g[1][kk]=1;
}
if(a[i][j]>0){
kk=tot[i][j];
g[kk][kk+1]=a[i][j];
make(i,j);
}
}
}//输入部分
int q=0,w=0;
while(jz())if(w=(find(1,100000000)))q+=w;//Dinic
ans=ans-q;
printf("%d\n",ans);
}