题目描述
在一个 r 行 c 列的网格地图中有一些高度不同的石柱,第 i 行 j 列的石柱高度为 hi,j。
一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。
每行每列中相邻石柱的距离为 11,蜥蜴的跳跃距离是 d,即蜥蜴可以跳到平面距离不超过 d 的任何一个石柱上。
石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减 11(如果仍然落在地图内部,则到达的石柱高度不变)。
如果该石柱原来高度为 11,则蜥蜴离开后消失,以后其他蜥蜴不能落脚。
任何时刻不能有两只蜥蜴在同一个石柱上。
输入格式
输入格式
输入第一行为三个整数 r,c,d,即地图的规模与最大跳跃距离。
接下来 r 行每行 c 个数字为石柱的初始状态,00 表示没有石柱,否则表示石柱的初始高度 h i,j。
接下来 r 行每行 c 个字符为蜥蜴位置,L
表示蜥蜴,.
表示没有蜥蜴。
输出格式
输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。
输入输出样例
输入 #1复制
5 8 2 00000000 02000000 00321100 02000000 00000000 ........ ........ ..LLLL.. ........ ........
输出 #1复制
1
说明/提示
对于 100%100% 的数据满足:1≤r,c≤20,1≤d≤4,1≤ℎ≤3。
Code
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
queue <int> q;
const int maxn=807;
const int maxm=100007;
const int inf=0x7f7f7f7f;
struct E{
int u,v,cf;
}e[maxm];//cf是指流量
#define cf(i) e[i].cf
int first[maxn],nt[maxm],ES=1;
inline void addE(int u,int v,int cf)
{
e[++ES]=(E){u,v,cf};
nt[ES]=first[u];
first[u]=ES;
return ;
}
inline void add(int u,int v,int cf)
{
addE(u,v,cf);addE(v,u,0);
return ;
}
int N,M,S,T;
char m1[27][27],m2[27][27];
inline int num(int i,int j)
{
return (i-1)*M+j;
}
int d,all,ans;
inline void linkE(int u,int i,int j)//从u连向 (i,j)
{
if(i<1||i>N||j<1||j>M)//落在图外直接连到T
{
add(u,T,inf);
return ;
}
if(m1[i][j]=='0') return ;
add(u,num(i,j),inf);
return ;
}
inline void link(int i,int j)//点(i,j)连边
{
if(m1[i][j]=='0') return ;
add(num(i,j),num(i,j)+all,m1[i][j]-'0');
if(m2[i][j]=='L')
add(S,num(i,j),1),ans++;//蜥蜴,顺便统计蜥蜴只数
if(i==1||j==1||i==N||j==M)
add(num(i,j)+all,T,inf);
int u=num(i,j)+all;
//没营养的一部分
if(d>=1)
{
linkE(u,i-1,j);linkE(u,i+1,j);
linkE(u,i,j-1);linkE(u,i,j+1);
}
if(d>=2)
{
linkE(u,i-2,j);linkE(u,i+2,j);
linkE(u,i,j-2);linkE(u,i,j+2);
linkE(u,i-1,j-1);linkE(u,i-1,j+1);
linkE(u,i+1,j-1);linkE(u,i+1,j+1);
}
if(d>=3)
{
linkE(u,i-3,j);linkE(u,i+3,j);linkE(u,i,j-3);linkE(u,i,j+3);
linkE(u,i-2,j-2);linkE(u,i-2,j+2);linkE(u,i+2,j-2);linkE(u,i+2,j+2);
linkE(u,i-1,j-2);linkE(u,i-1,j+2);linkE(u,i+1,j-2);linkE(u,i+1,j+2);
linkE(u,i-2,j-1);linkE(u,i-2,j+1);linkE(u,i+2,j-1);linkE(u,i+2,j+1);
}
if(d>=4)
{
linkE(u,i-4,j);linkE(u,i+4,j);linkE(u,i,j-4);linkE(u,i,j+4);
linkE(u,i-1,j-3);linkE(u,i-1,j+3);linkE(u,i+1,j-3);linkE(u,i+1,j+3);
linkE(u,i-3,j-1);linkE(u,i-3,j+1);linkE(u,i+3,j-1);linkE(u,i+3,j+1);
linkE(u,i-3,j-2);linkE(u,i-3,j+2);linkE(u,i+3,j-2);linkE(u,i+3,j+2);
linkE(u,i-2,j-3);linkE(u,i-2,j+3);linkE(u,i+2,j-3);linkE(u,i+2,j+3);
}
return ;
}
//Dinic最大流部分
int cur[maxn],cnt[maxn];
inline bool BFS()
{
memset(cnt,0,sizeof(cnt));
cnt[S]=1;
q.push(S);
int u,v;
while(!q.empty())
{
u=q.front();q.pop();
for(register int i=first[u];i;i=nt[i])
{
v=e[i].v;
if(cf(i)>0&&!cnt[v])
{
cnt[v]=cnt[u]+1;
q.push(v);
}
}
}
return cnt[T]!=0;
}
inline int dfs(int u,int f)
{
if(u==T) return f;
int d,v,sum=0;
for(register int &i=cur[u];i;i=nt[i])//cur数组是当前弧优化
{
v=e[i].v;
if(cf(i)>0&&cnt[v]==cnt[u]+1)
{
d=dfs(v,min(f,cf(i)));
if(d>0)
{
f-=d;sum+=d;
cf(i)-=d;cf(i^1)+=d;
if(f<=0) return sum;
}
}
}
return sum;
}
int main()
{
scanf("%d%d%d",&N,&M,&d);
T=N*M*2+1;all=N*M;//入点编号为u的点的出点为u + all
for(register int i=1;i<=N;i++)
scanf("%s",m1[i]+1);
for(register int i=1;i<=N;i++)
scanf("%s",m2[i]+1);
for(register int i=1;i<=N;i++)
for(register int j=1;j<=M;j++)
link(i,j);
while(BFS())
{
memcpy(cur,first,sizeof(cur));
ans-=dfs(S,inf);//流量都是跑出去的蜥蜴,要求剩下的蜥蜴。
//在连边函数里面已经统计了蜥蜴数量,减去就可以
}
printf("%d",ans);
return 0;
}