网络流中的最小路径覆盖问题

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流中的最小路径覆盖问题相关的知识,希望对你有一定的参考价值。

网络流中的最小路径覆盖问题

建图方式:

  • 拆成两个点(源点连p1,p2连汇点)
  • -对于边 ( u , v ) (u,v) (u,v),连 ( u p 1 , v p 2 ) (u_p_1,v_p_2) (up1,vp2)
  • 容量都为1。

总点数-最大流就是答案。

// Problem: P2172 [国家集训队]部落战争
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2172
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-12-02 16:06:39
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=55,M=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const int hashmod[4] = 402653189,805306457,1610612741,998244353;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define ios ios::sync_with_stdio(false),cin.tie(nullptr) 
void Print(int *a,int n)
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 

template <typename T>		//x=max(x,y)  x=min(x,y)
void cmx(T &x,T y)
	if(x<y) x=y;

template <typename T>
void cmn(T &x,T y)
	if(x>y) x=y;

int n,m,R,C;
const int NN=5e3+5;
struct Dinic
//Dinic O(n^2m)
	int st,ed;
	int id(int x,int y,int op=0)
		return !op?(x-1)*m+y:(n*m+(x-1)*m+y);
	
	struct edge
		int to,nt;
		ll w;
	e[M];
	int h[NN],cur[NN],cnt,dep[NN];
	void init(int _st,int _ed)
		st=_st,ed=_ed;
		cnt=1;mst(h,0);
	
	Dinic(int _st=0,int _ed=0)init(_st,_ed);
	void add(int u,int v,ll w)
		e[++cnt]=v,h[u],w,h[u]=cnt;
		e[++cnt]=u,h[v],0,h[v]=cnt;
	
	ll dfs(int u,ll c)	//search for augment path
		if(u==ed) return c;
		ll res=c;
		for(int &i=cur[u];i;i=e[i].nt)
			int v=e[i].to; ll w=e[i].w;
			if(w&&dep[v]==dep[u]+1)
				ll now=dfs(v,min(res,w));
				if(!now) dep[v]=1;
				else e[i].w-=now,e[i^1].w+=now,res-=now;
			
			if(!res) return c;
		return c-res;
	 
	bool bfs()		//layer the graph
		queue<int>q;q.push(st);mst(dep,0),dep[st]=1;
		while(!q.empty())
			int u=q.front();q.pop();cur[u]=h[u];
			for(int i=h[u];i;i=e[i].nt)
				int v=e[i].to;ll w=e[i].w;
				if(w&&!dep[v]) dep[v]=dep[u]+1,q.push(v);
			
		return dep[ed];
	 
	ll dinic()
		ll s=0;
		while(bfs()) s+=dfs(st,inf);
		return s;
	
G;
char a[N][N];
int dx[4];
int dy[4];
int main()
	scanf("%d%d%d%d",&n,&m,&R,&C);
	dx[0]=dx[1]=R,dx[2]=dx[3]=C;
	dy[0]=C,dy[1]=-C,dy[2]=R,dy[3]=-R;
	rep(i,1,n) scanf("%s",a[i]+1);
	int cnt = n*m,ed = cnt * 2 +1;
	G.init(0,ed);
	rep(i,1,n)
		rep(j,1,m)
			if(a[i][j]=='x') cnt--;
			else 
				G.add(G.st,G.id(i,j),1);
				G.add(G.id(i,j,1),G.ed,1);
				for(int k=0;k<4;k++)
					int nx = i + dx[k],ny = j + dy[k];
					if(nx>=1&&nx<=n&&ny>0&&ny<=m&&a[nx][ny]=='.')
						G.add(G.id(i,j),G.id(nx,ny,1),1);
					
				
			
		
	printf("%lld\\n",cnt-G.dinic());
	return 0;

P2764 最小路径覆盖问题

板题,要输出方案。

考虑用并查集维护,每个路径的起点。然后dfs即可。

// Problem: P2172 [国家集训队]部落战争
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2172
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-12-02 16:06:39
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=305,M=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const int hashmod[4] = 402653189,805306457,1610612741,998244353;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr) 
void Print(int *a,int n)
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 

template <typename T>		//x=max(x,y)  x=min(x,y)
void cmx(T &x,T y)
	if(x<y) x=y;

template <typename T>
void cmn(T &x,T y)
	if(x>y) x=y;

int n,m,R,C;
const int NN=305;
struct Dinic
//Dinic O(n^2m)
	int st,ed;
	struct edge
		int to,nt;
		ll w;
		int u;
	e[M];
	int h[NN],cur[NN],cnt,dep[NN],nt[N];
	void init(int _st,int _ed)
		st=_st,ed=_ed;
		cnt=1;mst(h,0);
	
	Dinic(int _st=0,int _ed=0)init(_st,_ed);
	void add(int u,int v,ll w)
		e[++cnt]=v,h[u],w,u,h[u]=cnt;
		e[++cnt]=u,h[v],0,v,h[v]=cnt;
	
	ll dfs(int u,ll c)	//search for augment path
		if(u==ed) return c;
		ll res=c;
		for(int &i=cur[u];i;i=e[i].nt)
			int v=e[i].to; ll w=e[i].w;
			if(w&&dep[v]==dep[u]+1)
				ll now=dfs(v,min(res,w));
				if(!now) dep[v]=1;
				else e[i].w-=now,e[i^1].w+=now,res-=now;
			
			if(!res) return c;
		return c-res;
	 
	bool bfs()		//layer the graph
		queue<int>q;q.push(st);mst(dep,0),dep[st]=1;
		while(!q.empty())
			int u=q.front();q.pop();cur[u]=h[u];
			for(int i=h[u];i;i=e[i].nt)
				int v=e[i].to;ll w=e[i].w;
				if(w&&!dep[v]) dep[v]=dep[u]+1,q.push(v);
			
		return dep[ed];
	 
	ll dinic()
		ll s=0;
		以上是关于网络流中的最小路径覆盖问题的主要内容,如果未能解决你的问题,请参考以下文章

最小路径覆盖问题网络流24题

[网络流24题] 最小路径覆盖问题

网络流24题之 1738: 最小路径覆盖问题

[网络流24题] 最小路径覆盖问题

最小路径覆盖问题(网络流,二分图) & 最小路径点覆盖结论证明

网络流24题 最小路径覆盖问题