[SCOI2007]蜥蜴

题目背景
07四川省选

题目描述
在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。

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

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

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

输入输出样例
输入 #1 复制

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

输出 #1 复制

1

说明/提示
100%的数据满足:1<=r, c<=20, 1<=d<=4


做网络流做得比较多的人应该一下子就能看出这是一个最大流。


考虑建图:网络流的重点就是建图,已经最大流的含义,建图的意义。

建立超级源点S,以及超级汇点T。

最大流的含义:让能跑出去的蜥蜴最多,就是最大流。
对于蜥蜴所在点,我们可以让S连向蜥蜴所在点。
对于每次离开,石柱高度减一,相当于就是限制了每个石柱的流量,所以我们拆点限流即可。
对于石柱之间的跳跃:我们枚举当前石柱能到达的点即可,若能到达就连流量inf的边。
对于每个石柱,如果能跳出去,我们就连向T,流量为inf。

最后跑一次最大流即可,答案就是蜥蜴总数减去最大流。


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e4+10,M=1e5+10;
int n,m,d,h[N],s,t,base,res;
int head[N],nex[M],to[M],w[M],tot=1;
char g[25][25];
inline void ade(int a,int b,int c){
	to[++tot]=b; w[tot]=c; nex[tot]=head[a]; head[a]=tot;
}
inline void add(int a,int b,int c){
	ade(a,b,c);	ade(b,a,0);
}
inline int get(int x1,int y1,int x2,int y2){
	return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
inline int id(int x,int y){
	return m*(x-1)+y;
}
int bfs(){
	memset(h,0,sizeof h);	queue<int> q;	q.push(s);	h[s]=1;
	while(q.size()){
		int u=q.front();	q.pop();
		for(int i=head[u];i;i=nex[i]){
			if(!h[to[i]]&&w[i]){
				q.push(to[i]);	h[to[i]]=h[u]+1;
			}
		}
	}
	return h[t];
}
int dfs(int x,int f){
	if(x==t)	return f;
	int fl=0;
	for(int i=head[x];i&&f;i=nex[i]){
		if(h[to[i]]==h[x]+1&&w[i]){
			int mi=dfs(to[i],min(w[i],f));
			w[i]-=mi;	w[i^1]+=mi;	fl+=mi;	f-=mi;
		}
	}
	if(!fl)	h[x]=-1;
	return fl;
}
int dinic(){
	int res=0;
	while(bfs())	res+=dfs(s,inf);
	return res;
}
signed main(){
	cin>>n>>m>>d;	s=0;	t=n*m*2+1;	base=n*m;
	for(int i=1;i<=n;i++)	for(int j=1;j<=m;j++)	cin>>g[i][j];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			char x;	cin>>x;	if(x=='.')	continue;	res++;
			add(s,id(i,j),1);
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(!(g[i][j]-'0'))	continue;
			add(id(i,j),id(i,j)+base,g[i][j]-'0');
			if(i-d<1||i+d>n||j-d<1||j+d>m)	add(id(i,j)+base,t,inf);
			for(int k=1;k<=n;k++){
				for(int s=1;s<=m;s++){
					if(k==i&&j==s||!(g[i][j]-'0'))	continue;
					if(d*d>=get(i,j,k,s))	add(id(i,j)+base,id(k,s),inf);
				}
			}
		}
	}
	cout<<res-dinic()<<endl;
	return 0;
}
全部评论

相关推荐

Java抽象带篮子:难蚌,点进图片上面就是我的大头😆
点赞 评论 收藏
分享
AFBUFYGRFHJLP:直接去美帝试试看全奖phd吧
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务