P2172

前言

这是发的第二篇网络流题解了。

思路

我们一读完题目就能想到的就是要拆点,我们就可以将一个下标为 \(x\)\(y\) 的点拆成 \(x\times m+y\) 以及 \((x+n)\times m+y\) 就行,然后我们再来进一步思考就能够发现这不就是最小路径覆盖吗?那么我们就能知道答案等于总成整数减去最大流。然后我们就可以来思考如何建图了,其实和模板差不多还是拆了后先将不加 \(n\times m\) 的点连上原点一条流量为 \(1\),再将加 \(n\times m\) 的连上汇点一条流量为 \(1\) 的点,最后看一下它能到达的四个点是否符合要求,若符合则将它与能到达的点加上 \(n\times m\) 连上一条边,再跑最大流即可。

代码

#include <bits/stdc++.h>
using namespace std ;
#define int long long
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define rep1(ix,u,y) for(int ix=u;ix>=y;ix--)
#define fire signed
const int M=1e6+10;
int tot=1,head[M],s,t;
int d[M],n,m,r,c;
struct node {
	int x,y,z;
} edg[M];
inline void add(int x,int y,int z) {//模板不讲 
	edg[++tot].x=y;
	edg[tot].y=head[x];
	edg[tot].z=z;
	head[x]=tot;
	edg[++tot].x=x;
	edg[tot].y=head[y];
	edg[tot].z=0;
	head[y]=tot;
}
inline bool bfs() {//模板不讲 
	memset(d,0,sizeof d);
	queue<int>q;
	q.push(s);
	d[s]=1;
	while(!q.empty()) {
		int x=q.front();
		q.pop();
		for(int i=head[x]; i; i=edg[i].y) {
			int j=edg[i].x;
			if(edg[i].z&&!d[j]) {
				q.push(j);
				d[j]=d[x]+1;
				if(j==t) return 1;
			}
		}
	}
	return false;
}
inline int Dinic(int x,int res) { //模板不讲 
	if(x==t) return res;
	int plus=res,k=0;
	for(int i=head[x]; i&&plus; i=edg[i].y) {
		if(edg[i].z&&d[edg[i].x]==d[x]+1) {
			int j=edg[i].x;
			k=Dinic(j,min(plus,edg[i].z));
			if(!k) d[j]=0;
			edg[i].z-=k;
			edg[i^1].z+=k;
			plus-=k;
		}
	}
	return res-plus;
}
char a[1010][1010];
int id(int x,int y) { //运用哈希求一个特殊值 
	return x*m+y;
}
int dx[5],dy[5];
fire main() {
	cin>>n>>m>>r>>c;
	s=0;
	dx[1]=r,dx[2]=r,dx[3]=dx[4]=c;
	dy[1]=c,dy[2]=-c;
	dy[3]=r;
	dy[4]=-r;
	int cnt=0;
	vector<pair<int,int> >v;
	t=2*(n+1)*m+1;
	rep(i,1,n) {
		rep(j,1,m) {
			cin>>a[i][j];
			if(a[i][j]=='.') {
				v.push_back(make_pair(i,j)); //记录 
				cnt++; //统计城镇数 
			}
		}
	}
	rep(i,0,cnt-1) {
		int x=v[i].first,y=v[i].second;
		add(s,id(x,y),1);//连原点 
		add(n*m+id(x,y),t,1); //连汇点 
		rep(i,1,4) { //看周围四个点 
			int tx=x+dx[i],ty=y+dy[i];
			if(tx<1||ty<1||tx>n||ty>m||a[tx][ty]!='.') continue; //不符合要求 
			add(id(x,y),n*m+id(tx,ty),1); //否则就连上一条 
		}
	}
	while(bfs()) cnt-=Dinic(s,INT_MAX); //减去最大流 
	cout<<cnt<<endl;
	return false;
}
posted @ 2024-01-31 11:26  highkj  阅读(18)  评论(0)    收藏  举报