P2472-[SCOI2007]蜥蜴【网络流】

正题

题目链接:https://www.luogu.com.cn/problem/P2472


题目大意

n ∗ m n*m nm个格子,每个格子的石柱高度不同,蜥蜴可以跳到距离不超过 d d d的石柱处,并且先前所站的石柱高度减一,为0则不能站,然后求有多少只蜥蜴不可以逃脱。


解题思路

考虑网络流,每只蜥蜴表示一个流,将每个石柱分成入点和出点,然后入点连出点流量为石柱高度,然后每个可以走的点之间出点连入点无限,之后有蜥蜴的柱子原点连入点流量为1,可以逃脱的出点连汇点。

然后dinic即可。


c o d e code code

#include
#include
#include
#include
#define p(x,y,w) ((((x)-1)*m+(y))*2-w)
using namespace std;
const int N=1e5+10,M=4e5+10,inf=2147483647/3;
struct node{
	int to,next,w;
}a[M];
int n,m,tot=1,s,t,d,ans;
int ls[N],dep[N];
char str[30];
queue<int> q;
void addl(int x,int y,int w){
	a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
	a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
	return;
}
int dis(int x1,int y1,int x2,int y2)
{return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);}
void connect(int x,int y){
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(dis(x,y,i,j)<=d*d&&(i!=x||j!=y))
				addl(p(x,y,1),p(i,j,0),inf);
	return;
}
bool bfs(){
	memset(dep,0,sizeof(dep));
	while(!q.empty())q.pop();
	q.push(s);dep[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=ls[x];i;i=a[i].next){
			int y=a[i].to;
			if(!a[i].w||dep[y])continue;
			dep[y]=dep[x]+1;
			if(y==t)return 1;
			q.push(y);
		}
	}
	return 0;
}
int dinic(int x,int flow){
	int rest=0,k;
	if(x==t)return flow;
	for(int i=ls[x];i;i=a[i].next){
		int y=a[i].to;
		if(!a[i].w||dep[y]!=dep[x]+1)continue;
		rest+=(k=dinic(y,min(flow-rest,a[i].w)));
		a[i].w-=k;a[i^1].w+=k;
		if(rest==flow)return flow;
	}
	if(!rest)dep[x]=0;
	return rest;
}
void net_work(){
	while(bfs())
		ans-=dinic(s,inf);
}
int main()
{
	scanf("%d%d%d",&n,&m,&d);
	s=p(n,m,0)+1;t=s+1;
	for(int i=1;i<=n;i++){
		scanf("%s",str+1);
		for(int j=1;j<=m;j++){
			addl(p(i,j,0),p(i,j,1),str[j]-'0');
			connect(i,j);
		}
	}
	for(int i=1;i<=n;i++){
		scanf("%s",str+1);
		for(int j=1;j<=m;j++){
		if(str[j]=='L')addl(s,p(i,j,0),1),ans++;
			if(i<=d||j<=d||n-i<d||m-j<d)
				addl(p(i,j,1),t,inf);
		}
	}
	net_work();
	printf("%d",ans);
}

你可能感兴趣的:(图论)