bzoj 1066: [SCOI2007]蜥蜴(最大流)

1066: [SCOI2007]蜥蜴

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 4116   Solved: 2081
[ 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


一眼网络流,其实感觉像这种怪怪的情况特复杂但数据特别小的题一般都是网络流

要拆点:将每个柱子拆成一个入点和一个出点

①所有的源点向有蜥蜴的点(入点)连一条流量为1的边

②所有能跳出去的柱子的出点向汇点连一条流量为无穷的边

③所有能相互跳的柱子,其中一个柱子的出点向另一个柱子的入点连一条流量为无穷的边

(注意A能到B,B也能到A)

一个柱子的入点向这个柱子的出点连接一条长度为柱子高度的边

然后答案就是蜥蜴个数 - 最大流


#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
#define LL long long 
#define inf 2147483647
using namespace std;
char str[25][25];
LL n, m, cnt, S, T, head[2005], h[2005], cur[2005];
typedef struct
{
	LL to, next;
	LL flow;
}Road;
Road G[20005];
void Add(LL u, LL v, LL flow)
{
	cnt++;
	G[cnt].next = head[u];
	head[u] = cnt;
	G[cnt].to = v;
	G[cnt].flow = flow;
}
int Jud()
{
	LL now, i;
	queue<int> q;
	memset(h, -1, sizeof(h));
	q.push(S);
	h[S] = 0;
	while(q.empty()==0)
	{
		now = q.front();
		q.pop();
		for(i=head[now];i!=0;i=G[i].next)
		{
			if(G[i].flow && h[G[i].to]==-1)
			{
				h[G[i].to] = h[now]+1;
				q.push(G[i].to);
			}
		}
	}
	if(h[T]!=-1)
		return 1;
	return 0;
}
LL Sech(LL x, LL flow)			//每次传入的flow是能经经过当前节点的最大流量
{
	LL w, used, i;
	if(x==T)
		return flow;
	used = 0;
	for(i=cur[x];i!=0;i=G[i].next)
	{
		if(h[G[i].to]==h[x]+1)
		{
			w = Sech(G[i].to, min(flow-used, G[i].flow));
			G[i].flow -= w;
			G[i^1].flow += w;
			if(G[i].flow)
				cur[x] = i;
			used += w;
			if(used==flow)		//如果当前节点都已经满流了(当然都能到达汇点),就没必要再往下搜了
				return flow;
		}
	}
	if(used==0)				//如果经过这个点的水流没有一滴都到达汇点,这给点已经无法再增广,屏蔽
		h[x] = -1;
	return used;
}
LL Dinic()
{
	LL i, flow = 0;
	while(Jud())
	{
		for(i=S;i<=T;i++)
			cur[i] = head[i];
		flow += Sech(S, inf);
	}
	return flow;
}
int main(void)
{
	int n, m, i, j, k, f, d, sum;
	while(scanf("%d%d%d", &n, &m, &d)!=EOF)
	{
		cnt = 1;
		S = 0, T = 2*n*m+1;
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
				scanf(" %c", &str[i][j]);
		}
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
			{
				if(str[i][j]=='0')
					continue;
				if(i<=d || n-i<d || j<=d || m-j<d)
				{
					Add(m*(n+i-1)+j, T, inf);
					Add(T, m*(n+i-1)+j, 0);
				}
				for(k=max(i-d, 1);k<=min(n, i+d);k++)
				{
					for(f=max(j-d, 1);f<=min(m, j+d);f++)
					{
						if(str[k][f]=='0')
							continue;
						if(k==i && j==f)
						{
							Add(m*(i-1)+j, m*(n+i-1)+j, str[k][f]-'0');
							Add(m*(n+i-1)+j, m*(i-1)+j, 0);
						}
						if(d*d>=(k-i)*(k-i)+(f-j)*(f-j))
						{
							Add(m*(n+i-1)+j, m*(k-1)+f, inf);
							Add(m*(k-1)+f, m*(n+i-1)+j, 0);
						}
					}
				}
			}
		}
		sum = 0;
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
			{
				scanf(" %c", &str[i][j]);
				if(str[i][j]!='.')
				{
					sum++;
					Add(S, m*(i-1)+j, 1);
					Add(m*(i-1)+j, S, 0);
				}
			}
		}
		printf("%d\n", sum-Dinic());
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值