蜥蜴【网络流】

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


##思路:
很明显的最大流问题。为了满足一个石柱最多跳a[i][j]a[i][j]只蜥蜴,就要将每个石柱进行拆点,中间流量为a[i][j]a[i][j],这样就保证了最多只有a[i][j]a[i][j]只蜥蜴可以跳这个石柱。那么这个建图就很明显了:

  1. 将源点SS向每个有蜥蜴的柱子连边,边权为1。
  2. 将与边界距离不足dd的柱子与汇点TT连边,边权为INFINF
  3. 将拆好的柱子两两连边,边权为a[i][j]a[i][j]
  4. 将直线距离不大于dd的柱子连边,边权为INFINF

跑一边最大流即可得到能逃出的蜥蜴数量,再用总蜥蜴数量减去得到的答案即可。


##代码:

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#define Inf 0x7f
#define INF 1e9
using namespace std;

int n,m,d,a[41][41],head[500001],dep[500001],s,t,k,ans,num,sum,x,y;
char c;

struct edge
{
	int next,to,c;
}e[500001];

void add(int from,int to,int c)
{
	k++;
	e[k].c=c;
	e[k].to=to;
	e[k].next=head[from];
	head[from]=k;
} 

bool check(int x1,int y1,int x2,int y2)
{
	return ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=d*d);
	//计算两个柱子的直线距离
	//两边同时开方得 sqrt((x1-x2)^2+(y1-y2)^2)<=d
	//再利用毕达哥拉斯定理计算
}

bool bfs()  //分层
{
	queue<int> q;
	q.push(s);
	memset(dep,Inf,sizeof(dep));
	dep[s]=0;
	while (q.size())
	{
		int u=q.front();
		q.pop();
		for (int i=head[u];i;i=e[i].next)
		{
			int v=e[i].to;
			if (dep[v]>dep[u]+1&&e[i].c)  
			{
				dep[v]=dep[u]+1;
				q.push(v);
			}
		}
	} 
	return (dep[t]<Inf);
}

int dfs(int u,int low)
{
	int lows=0;
	if (u==t) return low;
	for (int i=head[u];i;i=e[i].next)
	{
		int v=e[i].to;
		if (dep[v]==dep[u]+1&&e[i].c)
		{
			lows=dfs(v,min(low,e[i].c));
			if (!lows) continue;
			e[i].c-=lows;  //正向边
			e[(i+1)^1-1].c+=lows;  //反向边
			return lows;
		}
	}
	return 0;
}

int main()
{
	scanf("%d%d%d",&n,&m,&d);
	s=0;
	t=n*m*2+1;
	 //柱子a编号为1~n*m,柱子b编号为n*m+1~2*n*m
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=m;j++)
	 {
	 	scanf("%1d",&a[i][j]);
	 	x=(i-1)*m+j;  //计算编号
	 	add(x,x+n*m,a[i][j]);
	 	add(x+n*m,x,0);  //柱子a和柱子b连接
	 	if (i-d<1||i+d>n||j-d<1||j+d>m)  //能跳到边界外
	 	{
	 		add(x+n*m,t,INF);
	 		add(t,x+n*m,0);  //与t相连
	 	}
	 }
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=m;j++)
	 {
	 	cin>>c;
	 	if (c=='L')  //蜥蜴
	 	{
	 		num++;
	 		x=(i-1)*m+j;
	 		add(s,x,1);
	 		add(x,s,0);  //与s相连
	 	}
	 }
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=m;j++)
	  for (int k=1;k<=n;k++)
	   for (int l=1;l<=m;l++)
	    if (check(i,j,k,l))  //距离不大于d
	    {
	    	x=(i-1)*m+j;
	    	y=(k-1)*m+l;
	    	add(x+n*m,y,INF);
	    	add(y,x+n*m,0);
	    	add(y+n*m,x,INF);
	    	add(x,y+n*m,0);
	    }
	while (bfs())
	{
		while (sum=dfs(s,INF))
		 ans+=sum;
	}
	printf("%d\n",num-ans);
	return 0;
}
原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998808.html