[bzoj]1066: [SCOI2007]蜥蜴

原题链接:蜥蜴


理解很重要,理解很重要,理解很重要!!


分析:

看到这题首先可能会想到搜索:裸图??
但是很明显搜索肯定会超时
观察题目,发现每根柱子有跳跃次数上限,想到了什么??
网络流!!
题目中有坑,每根柱子上只能站一只蜥蜴这个条件其实是没用的。
因为蜥蜴不动的话对柱子高度是没有影响的,只要按顺序跳跃就行了。
那么怎么考虑跳跃次数呢?
可以把每个柱子拆成两个点,一个入点一个出点,从入点到出点有单向流量,流量大小为柱子的高度。
从超级源向每一个蜥蜴的初始点的入点连流量为1的边。
每个能跳出去的点向超级汇连流量为无穷大的边。
再把所有柱子向能跳达的柱子连边,流量为无穷大。
这样子网络流模型就出来了,我们只需要从源点开始跑一遍最大流,然后拿蜥蜴的总个数减去最大流就是我们的答案了。


注意!
第一次写的时候不知道写挂什么了,输出答案一直不对,调错调了一个半小时没有结果,然后重写一遍就对了。所以说如果发现查不出错的话一定要果断重构!!


下面是代码
#include <iostream>
#include <queue>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int inf=0x7fffffff;
int rr,cc,dd,g[25][25],d[5000],s=0,t=1000,mark[25][25];
int ver[500000],head[5000],next[500000],edge[500000],tot=1;
queue <int> q;
void add(int x,int y,int val){
	ver[++tot]=y;edge[tot]=val;next[tot]=head[x];head[x]=tot;
	ver[++tot]=x;edge[tot]=0;next[tot]=head[y];head[y]=tot;
}
bool judge(int x1,int y1,int x2,int y2){
	if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)>dd*dd)return false;
	else if(g[x1][y1]&&g[x2][y2])return true;
}
bool bfs();
int dinic(int x,int flow);
int main()
{
	//freopen("data.in","r",stdin);
	char ch[21];
	int num=0,ans=0,flow,maxflow=0;
	scanf("%d%d%d",&rr,&cc,&dd);
	for(int i=1;i<=rr;i++){
		scanf("%s",ch);
		for(int j=1;j<=cc;j++){
			g[i][j]=ch[j-1]-'0';
			mark[i][j]=++num;
			if(g[i][j])add(mark[i][j],mark[i][j]+400,g[i][j]);
		}
	}
	for(int i=1;i<=rr;i++){
		scanf("%s",ch);
		for(int j=1;j<=cc;j++){
			if(ch[j-1]=='L'){
				add(s,mark[i][j],1);
				ans++;
			}
		}
	}
	for(int i=1;i<=dd;i++){
		for(int j=1;j<=cc;j++){
			add(mark[i][j]+400,t,inf);
			add(mark[rr-i+1][j]+400,t,inf);
		}
	}
	for(int j=1;j<=dd;j++){
		for(int i=dd+1;i<=rr-dd;i++){
			add(mark[i][j]+400,t,inf);
			add(mark[i][cc-j+1]+400,t,inf);
		}
	}

	for(int i=1;i<=rr;i++)
		for(int j=1;j<=cc;j++)
			for(int p=(i-dd<=0)?1:i-dd;p<=min(rr,i+dd);p++)
				for(int q=(j-dd<=0)?1:j-dd;q<=min(cc,j+dd);q++)
					if(judge(i,j,p,q)&&(i!=p||j!=q))
						add(mark[i][j]+400,mark[p][q],inf);
    //cout<<1<<endl;
	while(bfs())
		while(flow=dinic(s,inf))maxflow+=flow;
	printf("%d\n",ans-maxflow);
	return 0;
}
bool bfs(){
	memset(d,0,sizeof(d));
	while(q.size())q.pop();
	q.push(s);d[s]=1;
	while(q.size()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=next[i]){
			if(edge[i]&&!d[ver[i]]){
				q.push(ver[i]);
				d[ver[i]]=d[x]+1;
				if(ver[i]==t)return true;
			}
		}
	}
	return false;
}
int dinic(int x,int flow){
	if(x==t)return flow;
	int res=flow,k;
	for(int i=head[x];i&&res;i=next[i]){
		if(edge[i]&&d[ver[i]]==d[x]+1){
			k=dinic(ver[i],min(flow,edge[i]));
			if(!k)d[ver[i]]=0;
			edge[i]-=k;
			edge[i^1]+=k;
			res-=k;
		}
	}
	return flow-res;
}
posted @ 2018-10-27 00:54  _onglu  阅读(156)  评论(0编辑  收藏  举报