I. Improving the Neighborhood(最大网络流模板题)

该文描述了一个图论问题,给定一个地图,包含可行、不可行区域、公园和学校,要求找到在不超过特定距离D内有公园和学校的房子。利用Dinic算法构建网络流模型,将房子、公园和学校转化为节点,寻找最大流量以确定满足条件的房子数量。
摘要由CSDN通过智能技术生成

题意:给你一个图,图上.,#,P,S,H分别代表可行区域,不可行区域,公园,学校,房子,再给你一个距离D,要求你所卖出的房子必须要一个公园和一个学校,这俩距离你所卖的房子不超过D

算法:dinic 将图拆成n个点,源点等于0,汇点等于2*n;

将房子拆成俩个点分别连接公园,学校

# include <bits/stdc++.h>
using namespace std;
#define f first
#define s second
# define int long long 
int l,c,D;
int s1,t;
const int inf=1<<29;
const int N=1000;
int dist[N][N];
int ids[N][N];
char m[N][N];
int varx[]= {0,0,1,-1};
int vary[]= {1,-1,0,0};
vector<pair<int,int>>house;
const int N1=50010,M=300010;
int ver[M],head[M],Next[M],edge[M];
int d[N1]; 
int tot=1;
void add(int x,int y,int z) {
	ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
	ver[++tot]=x,edge[tot]=0,Next[tot]=head[y],head[y]=tot;
}
int now[M];
bool bfs() {
	memset(d,0,sizeof(d));
	queue<int>q;
	while(q.size()) {
		q.pop();
	}
	q.push(s1);
	d[s1]=1;
	now[s1]=head[s1];
	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]);
				now[ver[i]]=head[ver[i]];
				d[ver[i]]=d[x]+1;
				if(ver[i]==t) {
					return 1;
				}
			}
		}
	}
	return 0;
}
int dinic(int x,int flow) {
	if(x==t) {
		return flow;
	}
	int rest=flow,k,i;
	for(i=now[x]; i&&rest; i=Next[i]) {
		now[x]=i;
		if(edge[i]&&d[ver[i]]==d[x]+1) {
			k=dinic(ver[i],min(rest,edge[i]));
			if(!k) {
             d[ver[i]]=0;  
			}
			edge[i]-=k;
			edge[i^1]+=k;
			rest-=k;
		}

	}
	return flow-rest;
}
void bfs1(int i,int j) {
	queue<pair<int,int>>q;
	q.push({i,j});
	dist[i][j]=0;
	while(!q.empty()) {
		auto x=q.front();
		q.pop();
		for(int k=0; k<4; k++) {
			int x1=x.f+varx[k];
			int y1=x.s+vary[k];
			if(m[x1][y1]=='S'||m[x1][y1]=='P') {
				if(dist[x1][y1]==-1) {
					dist[x1][y1]=1+dist[x.f][x.s];
				}
				continue ;
			}
			if(x1<1||x1>l||y1<1||y1>c||dist[x1][y1]!=-1||m[x1][y1]!='.') {
				continue ;
			}
			dist[x1][y1]=dist[x.f][x.s]+1;
			q.push({x1,y1});
		}
	}
}
signed main() {
	cin>>l>>c>>D;
	int cnt=0;
	for(int i=1; i<=l; i++) {
		for(int j=1; j<=c; j++) {
			cin>>m[i][j];
			ids[i][j]=++cnt;
			if(m[i][j]=='H') {
				house.push_back({i,j});
			}
		}
	}
	int n=++cnt;
	for(int i=1; i<=l; i++) {
		for(int j=1; j<=c; j++) {
             if(m[i][j]=='P')
             {
             	add(ids[i][j],2*n,1);
			 }
			 else if(m[i][j]=='S')
			 {
			 	   add(0,ids[i][j],1);
			 }
		}
	}
	for(auto x: house)
	{
		 memset(dist,-1,sizeof(dist));
		 bfs1(x.f,x.s);
		 add(ids[x.f][x.s],ids[x.f][x.s]+n,1);
		 for(int i=1;i<=l;i++)
		 {
		 	for(int j=1;j<=c;j++)
		 	{
		 		  if(m[i][j]=='S'&&dist[i][j]!=-1&&dist[i][j]<=D)
		 		  {
		 		  	  add(ids[i][j],ids[x.f][x.s],1); 
				   }
				   if(m[i][j]=='P'&&dist[i][j]!=-1&&dist[i][j]<=D)
				   {
				   	   add(ids[x.f][x.s]+n,ids[i][j],1);
				   }
			 }
		 }
	 } 
	 n*=2;
     s1=0;
     t=n;
     int flow=0;
     int maxflow=0;
     while(bfs())
     {
     	while(flow=dinic(s1,inf))
     	{
     		  maxflow+=flow;
		 }
	 }
	 cout<<maxflow<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值