【SCOI2007】蜥蜴(最大流)

版权声明:虽然我很菜,不过转载请标明出处。 https://blog.csdn.net/Patrickpwq/article/details/86653025

很显然柱子的高度就是边的容量 因为这个定义和容量很像

所以把柱子拆成两个点

然后之后就很显然了

源点先连接蜥蜴所在柱子上 容量为1 然后柱子之间符合距离要求的相连(注意是右端点连上左端点) 容量随意 然后能出去的柱子连汇点 容量随意 

然后注意细节

#include<bits/stdc++.h>
const int N=100005;
const int INF=0x3f3f3f3f;
using namespace std;
int r,c,d,cnt1,cnt2;
int s,t;
struct Data
{
	int x,y,h,pos;
}st[N],l[N];
inline int dis(Data L,Data S){ return (L.x-S.x)*(L.x-S.x)+(L.y-S.y)*(L.y-S.y); }
int first[2*N],tot=1;
struct Edge
{
	int to,next,cap;
}edge[2*N];
inline void addedge(int x,int y,int z)
{
	tot++;
	edge[tot].to=y; edge[tot].next=first[x]; edge[tot].cap=z; first[x]=tot;
} 
int step[2*N],cur[2*N];
bool bfs()
{
	memset(step,-1,sizeof(step));
	queue <int> q;
	q.push(s); step[s]=1; 
	while(!q.empty())
	{
		int now=q.front();
		q.pop();
		for(int u=first[now];u;u=edge[u].next)
		{
			int vis=edge[u].to;
			if(edge[u].cap>0&&step[vis]==-1)
			{
				step[vis]=step[now]+1;
				q.push(vis);
				if(vis==t)	return 1;
			}
		}
	}
	return 0;
}
int dfs(int now,int f)
{
	if(now==t||!f)	return f;
	int out=0;
	for(int &u=cur[now];u;u=edge[u].next)
	{
		int vis=edge[u].to;
		if(edge[u].cap&&step[vis]==step[now]+1)
		{
			int w=dfs(vis,min(f,edge[u].cap));
			if(!w)	continue;
			f-=w; out+=w;
			edge[u].cap-=w; edge[u^1].cap+=w;
			if(!f)	break;
		}
	}
	return out;
}
void Maxflow()
{
	int ans=0;
	while(bfs())
	{
		for(int i=1;i<=t;i++)	cur[i]=first[i];
		ans+=dfs(s,INF);
	}
	cout<<cnt2-ans<<endl;
}
int main()
{
	cin>>r>>c>>d;
	for(int i=1;i<=r;i++)
		for(int j=1;j<=c;j++)
		{
			char x;
			cin>>x;
			x=x-'0';
			if(x>0) st[++cnt1].x=i,st[cnt1].y=j,st[cnt1].h=x;	
		}
	for(int i=1;i<=r;i++)
		for(int j=1;j<=c;j++)
		{
			char x;
			cin>>x;
			if(x=='L') l[++cnt2].x=i,l[cnt2].y=j;
		}
	s=1; t=1+2*cnt1+1;
	for(int i=1;i<=cnt1;i++)	//石柱与石柱相连 
	{
		for(int j=1;j<=cnt1;j++)
		{
			if(i==j)	continue;
			if(dis(st[i],st[j])>d*d)	continue;
			addedge(1+i+cnt1,1+j,INF);	//右端朝左端连边 
			addedge(1+j,1+i+cnt1,0);
		}
	}
	for(int i=1;i<=cnt2;i++)	//枚举蜥蜴所在编号 
	{
		for(int j=1;j<=cnt1;j++)	//哪个石头和它是一样的 
		{
			if(l[i].x==st[j].x&&l[i].y==st[j].y)
			{
				l[i].pos=j;
				break;
			}
		}
	}
	for(int i=1;i<=cnt2;i++)	//源点与蜥蜴所在石柱 
	{
		addedge(s,1+l[i].pos,1);
		addedge(1+l[i].pos,s,0);
	}
	for(int i=1;i<=cnt1;i++)	//石柱左右端点 
	{
		addedge(1+i,1+i+cnt1,st[i].h);
		addedge(1+i+cnt1,1+i,0);
	}
	for(int i=1;i<=cnt1;i++)	//可以跳出去 
	{
		int R,C;
		R=st[i].x; C=st[i].y;
		if(R<=d||R+d>r||C<=d||C+d>c)
		{
			addedge(1+cnt1+i,t,INF);
			addedge(t,1+cnt1+i,0);
		}
	}
	Maxflow();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Patrickpwq/article/details/86653025
今日推荐