P2472 [SCOI2007] 蜥蜴

题目描述

在一个 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;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值