[bzoj 1066][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

HINT

100%的數據滿足:1<=r, c<=20, 1<=d<=3

題解

此題的難點就難在建圖

1.對於每個點 拆成兩個點 一個入點 一個出點 連一條權值爲高度的邊

2.對於每個有蜥蜴的點 超級源點 與他連一條 權值爲1的邊 (只能有一個蜥蜴)

3.對於可以跳出地圖的點 把他的出點與超級匯 連一條inf的邊

4.對於每可以跳到的點 起跳的出點 和到達的入點連一條inf的邊

剩下的就是跑最大流 然後用總數減去最大流即可

//http://www.lydsy.com/JudgeOnline/problem.php?id=1066
//較難的一題最大流 
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 0x7ffffff
using namespace std;
struct edge{int to,w,next;}e[500001];
int n,m,d,cnt=1,num=0;
int start=0,end=1000; //超級源點 和 超級匯點
int mp[30][30],bh[30][30];
int dis[1500],head[1500];
void ini(int x,int y,int z){
	e[++cnt].to=y;e[cnt].w=z;e[cnt].next=head[x];head[x]=cnt;
}
void insert(int x,int y,int z){
	ini(x,y,z);ini(y,x,0);
}
queue<int>q;
bool bfs(){
	q.push(start);
	memset(dis,-1,sizeof(dis));
	dis[start]=0;
	while(!q.empty()){
		int k=q.front();q.pop();
		for(int i=head[k];i;i=e[i].next){
			int kk=e[i].to;
			if(dis[kk]==-1&&e[i].w>0){
				dis[kk]=dis[k]+1;q.push(kk);
			}
		}
	}
	if(dis[end]==-1) return false;
	return true;
}
int dfs(int x,int mn){
	if(x==end) return mn;
	for(int i=head[x];i;i=e[i].next){
		int k=e[i].to;int a;
		if(dis[k]==dis[x]+1&&e[i].w>0&&(a=dfs(k,min(e[i].w,mn))))
		{
			e[i].w-=a;
			e[i^1].w+=a;
			return a;
		}
	}
	return 0;
}
bool excape(int x,int y)
{
    return min(min(x,n+1-x),min(y,m+1-y))<=d;
}
bool judge(int x1,int y1,int x2,int y2){
	if(x1==x2&&y1==y2) return false;
	return (mp[x1][y1]&&mp[x2][y2]&&(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=d*d);
}
void dinic(){
	int ans=0;
	while(bfs()){
		int a;
		while(a=dfs(start,inf))
			ans+=a;
	}
	printf("%d",num-ans);
}
int main(){
	scanf("%d%d%d",&n,&m,&d);
	char ch[30];
	int tot=0;
	for(int i=1;i<=n;i++){
		scanf("%s",ch+1);
		for(int j=1;j<=m;j++){
			mp[i][j]=ch[j]-'0';
			bh[i][j]=++tot;
		}
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%s",ch+1);
		for(int j=1;j<=m;j++)
		{
			if(ch[j]=='L'){
				insert(0,bh[i][j],1);
				num++;
			}
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(mp[i][j])
			insert(bh[i][j],bh[i][j]+400,mp[i][j]);//拆點
			if(excape(i,j)) insert(bh[i][j]+400,end,inf);//能走的話就連超級匯點
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			for(int t1=max(1,i-d);t1<=min(i+d,n);t1++)
				for(int t2=max(1,j-d);t2<=min(j+d,m);t2++)
					if(judge(i,j,t1,t2)) insert(bh[i][j]+400,bh[t1][t2],inf);
	 dinic();
	return 0;
}


發佈了98 篇原創文章 · 獲贊 46 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章