[bzoj1066] [SCOI2007]蜥蜴

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

Solution

拆点最大流,无脑暴力建边就好了。

具体的,设\(in(x)\)表示\(x\)的入点,\(out(x)\)表示出点。

  • 对于有蜥蜴的点\(x_i\),建\(<s,in(x_i),1>\)
  • 对于两个距离不超过\(d\)的点\(x,y\),建立\(<out(x),in(y),\infty>\)
  • 对于边界的点\(x\),建立\(<out(x),t,\infty>\)
  • 对于每个点\(x\),建立\(<in(x),out(x),w_x>\),其中\(w_x\)是点权。

然后我被降智dinic调了一小时

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;
const int inf = 1e9;

struct edge{int to,nxt,w;}e[maxn];
int head[maxn],tot=1,n,m,s,t,d,flow,vis[1000],dis[1000],mp[50][50];

void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
void ins(int u,int v,int w) {add(u,v,w),add(v,u,0);}
	
int calc(int x,int y,int z) {return (x-1)*m+y+n*m*z;}
 
#define sqr(x) ((x)*(x))
 
char ss[maxn];

int bfs() {
	memset(vis,0,sizeof vis);
	memset(dis,63,sizeof dis);
	queue<int > q;q.push(s),dis[s]=0,vis[s]=1;
	while(!q.empty()) {
		int now=q.front();q.pop();vis[now]=0;
		for(int i=head[now];i;i=e[i].nxt)
			if(e[i].w>0&&dis[e[i].to]>dis[now]+1) {
				dis[e[i].to]=dis[now]+1;
				if(!vis[e[i].to]) vis[e[i].to]=1,q.push(e[i].to);
			}
	}return dis[t]<inf;
}

int dfs(int x,int f) {
	if(x==t||!f) return flow+=f,f;
	int used=0;
	for(int i=head[x];i;i=e[i].nxt)
		if(e[i].w>0&&(x==t||!vis[e[i].to])&&dis[e[i].to]==dis[x]+1) {
			int dd=dfs(e[i].to,min(f-used,e[i].w));
			if(dd>0) e[i].w-=dd,e[i^1].w+=dd,used+=dd;
			if(used==f) break;
		}return used;
}

int dinic() {
	flow=0;while(bfs()) dfs(s,inf);return flow;
}

int main() {
	read(n),read(m),read(d);
	s=n*m*2+3,t=n*m*2+4;
	for(int i=1;i<=n;i++) {
		scanf("%s",ss+1);
		for(int j=1;j<=m;j++) ins(calc(i,j,0),calc(i,j,1),ss[j]-'0'),mp[i][j]=(ss[j]>'0');
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			for(int a=1;a<=n;a++)
				for(int b=1;b<=m;b++)
					if(mp[a][b]&&mp[i][j]&&sqr(a-i)+sqr(b-j)<=sqr(d))
						ins(calc(i,j,1),calc(a,b,0),inf);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(min(min(i,n-i+1),min(j,m-j+1))<=d) ins(calc(i,j,1),t,inf);
	int cnt=0;
	for(int i=1;i<=n;i++) {
		scanf("%s",ss+1);
		for(int j=1;j<=m;j++) if(ss[j]=='L') ins(s,calc(i,j,0),1),cnt++;
	}
	write(cnt-dinic());
	return 0;
}
posted @ 2019-02-21 17:06  Hyscere  阅读(140)  评论(0编辑  收藏  举报