bzoj1066 蜥蜴

1066: [SCOI2007]蜥蜴

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

bzoj上的第三道题目,第一道非水题......

其实就是一道简单的最大流问题,关键是建模,建完模之后直接复制模板就行了

把每两个石柱之间看做是一个点,石柱的高度就是这两个节点的容量
如图,a和b之间容量为3,b和c之间容量为2

下面是代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string.h>
#include <cmath>
#include <queue>
#define maxn 821396745
using namespace std;
int ans,tot,fin[1010][1010];
char high[1010][1010];
int n,m,s,t,f[11000],flow[11000],d,map[1000][1000];
queue <int> q;
void make(int x,int y)
{
	int now=fin[x][y]+1;  
	for(int i=1;i<=n;i++)  
		for(int j=1;j<=m;j++)  
    		if((i!=x||j!=y)&&(high[i][j]>'0'))  
			{  
				if(d>=sqrt((x-i)*(x-i)+(y-j)*(y-j)))  
					map[now][fin[i][j]]=maxn;  
    		}
}
void go()
{
	for(int i=1;i<=n;i++)  
		for(int j=1;j<=m;j++)  
			if(i-d<1||i+d>n||j-d<1||j+d>m)  
			{  
        		int de=fin[i][j]+1;  
				map[de][tot]=maxn;  
			}  
}
int bfs(int s,int t)
{
	while(!q.empty())
		q.pop();
	memset(f,-1,sizeof(f));
	f[s]=0;
	flow[s]=maxn;
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		if(u==t)	break;
		for(int v=1;v<=tot;v++)
		{
			if(map[u][v]>0&&f[v]==-1)
			{
				f[v]=u;
				flow[v]=min(flow[u],map[u][v]);
				q.push(v);
			}
		}
	}
	if(f[t]==-1)
		return -1;
	else 
		return flow[t];
}
int maxflow(int s,int t)
{
	int maxf=0;
	d=0;
    while((d=bfs(s,t))!=-1)
    {
    	int aim=t;
    	while(aim!=s)
    	{
    		map[f[aim]][aim]-=d;
    		map[aim][f[aim]]+=d;
    		aim=f[aim];
    	}
    	maxf+=d;
    }
    return maxf;
}
int main()
{
	scanf("%d%d%d",&n,&m,&d);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			cin>>high[i][j];
			if(high[i][j]!='0')
			{
				fin[i][j]=++tot;
				map[tot][++tot]=high[i][j]-'0';
			}
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			char cp;
			cin>>cp;
			if(cp=='L')
			{
				ans++;
				map[0][fin[i][j]]=1;
			}
			if(high[i][j]>'0')
				make(i,j);
		}
	tot++;
	go();
    printf("%d",ans-maxflow(0,tot));
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值