bzoj1066【SCOI2007】蜥蜴

1066: [SCOI2007]蜥蜴

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 2512   Solved: 1238
[ Submit][ Status][ Discuss]

Description

在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。

Input

输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。

Output

输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。

Sample Input

5 8 2
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........

Sample Output

1

HINT

100%的数据满足:1<=r, c<=20, 1<=d<=4

Source

<a href="http://www.lydsy.com/JudgeOnline/problemset.php?search=Pku%202711%20Leapin" lizards'="" style="color: blue; text-decoration: none;">Pku 2711 Leapin' Lizards




题目要求无法逃离的蜥蜴的最小值,即求可以逃离的蜥蜴的最大值。选择使用最大流,当然重点在构图。

对于每一个石柱,我们可以拆成两个点,分别为入点和出点。

对于所有石柱,从入点到出点连边,容量为高度。这里等于限制了每一个石柱的跳跃次数。

对于最初有蜥蜴的石柱,从源点向这些点的入点连边,容量为1。因为每一个石柱只有一个蜥蜴。

对于任意一对可以相互到达的石柱,分别从彼此的出点到入点连边,容量为正无穷。等于假设可以有尽可能多的蜥蜴跳过。

对于可以跳到边界外的石柱,从出点向汇点连边,容量为正无穷。原理同上。




#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define LL long long
#define pa pair<int,int>
#define MAXN 1000
#define MAXM 100000
#define INF 1000000000
#define f1(x,y) ((x-1)*m+y)
#define f2(x,y) ((x-1)*m+y+m*n)
using namespace std;
int cnt=1,ans=0,s,t,n,m,d;
int head[MAXN],cur[MAXN],dis[MAXN],f[25][25];
char ch[25];
struct edge_type
{
	int next,to,v;
}e[MAXM];
inline void add_edge(int x,int y,int v)
{
	e[++cnt]=(edge_type){head[x],y,v};head[x]=cnt;
	e[++cnt]=(edge_type){head[y],x,0};head[y]=cnt;
}
inline bool bfs()
{
	queue<int>q;
	while (!q.empty()) q.pop();
	memset(dis,-1,sizeof(dis));
	dis[s]=0;q.push(s);
	while (!q.empty())
	{
		int tmp=q.front();q.pop();
		if (tmp==t) return true;
		for(int i=head[tmp];i;i=e[i].next) if (e[i].v&&dis[e[i].to]==-1)
		{
			dis[e[i].to]=dis[tmp]+1;
			q.push(e[i].to);
		}
	}
	return false;
}
inline int dfs(int x,int f)
{
	int tmp,sum=0;
	if (x==t) return f;
	for(int &i=cur[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if (e[i].v&&dis[y]==dis[x]+1)
		{
			tmp=dfs(y,min(f-sum,e[i].v));
			e[i].v-=tmp;e[i^1].v+=tmp;sum+=tmp;
			if (sum==f) return sum;
		}
	}
	if (!sum) dis[x]=-1;
	return sum;
}
inline void dinic()
{
	while (bfs())
	{
		F(i,1,t) cur[i]=head[i];
		ans-=dfs(s,INF);
	}
}
inline bool excape(int x,int y)
{
	return min(min(x,n+1-x),min(y,m+1-y))<=d;
}
inline bool judge(int x1,int y1,int x2,int y2)
{
	if (x1==x2&&y1==y2) return false;
	return (f[x1][y1]&&f[x2][y2]&&((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))<=(d*d));
}
int main()
{
	scanf("%d%d%d",&n,&m,&d);s=2*n*m+1;t=s+1;
	F(i,1,n)
	{
		scanf("%s",ch);
		F(j,1,m) f[i][j]=ch[j-1]-'0';
	}
	F(i,1,n)
	{
		scanf("%s",ch);
		F(j,1,m) if (ch[j-1]=='L'){add_edge(s,f1(i,j),1);ans++;}
	}
	F(i,1,n) F(j,1,m) if (f[i][j])
	{
		add_edge(f1(i,j),f2(i,j),f[i][j]);
		if (excape(i,j)) add_edge(f2(i,j),t,INF);
	}
	F(i,1,n) F(j,1,m) F(ti,max(1,i-d),min(n,i+d)) F(tj,max(1,j-d),min(m,j+d))
		if (judge(i,j,ti,tj)) add_edge(f2(i,j),f1(ti,tj),INF);
	dinic();
	printf("%d\n",ans);
}


你可能感兴趣的:(网络流,bzoj)