【网络流24题】最小路径覆盖问题-二分图匹配/最大流

版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ" https://blog.csdn.net/corsica6/article/details/84403112

传送门:luogu P2764 最小路径覆盖问题


题解

结论: D A G DAG 的最小路径覆盖数等于点数-最大二分图匹配数。

一种证明方法:
初始每个点自身是一条路径(一共 n n 条),两个点匹配上代表两条不相交的路径连起来了,则路径数-1,每个点入度 1 \leq1 (最多被匹配一次)。
将每个点拆成 i , i i,i' (分别表示入度出度),边 ( x , y ) (x,y) 在二分图中为 ( x , y ) (x,y') ,则答案为 n n -二分图最大匹配数。

二分图最大匹配写起来比最大流简洁得多啊。


代码

#include<bits/stdc++.h>
using namespace std;
const int N=155;
typedef long long ll;

int n,m,g[N][N],bel[N],ans;
int vs[N],f[N],tim,id[N];
vector<int>a[N];

int getfa(int x){return x==f[x]?x:f[x]=getfa(f[x]);}

bool dfs(int x)
{
	for(int i=1;i<=n;++i) 
	  if(g[x][i] && (vs[i]!=tim)){
	    vs[i]=tim;
	    if((!bel[i])||dfs(bel[i])){
	    	bel[i]=x;return true;
	    }
	  }
	return false;
}

int main(){
	int i,j,x,y;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;++i){
		scanf("%d%d",&x,&y);
		g[x][y]=1;
	}
	for(i=1;i<=n;++i){tim++;f[i]=i;dfs(i);}
	for(i=1;i<=n;++i) if(bel[i]) {
	   x=getfa(i);y=getfa(bel[i]);f[x]=y;
	}
	for(tim++,i=1;i<=n;++i){
		if(!id[getfa(i)]) id[getfa(i)]=++ans;
		a[id[getfa(i)]].push_back(i);
	}
	for(i=1;i<=ans;++i){
		x=a[i].size();
		for(j=0;j<x;++j) printf("%d ",a[i][j]);
		puts("");
	}
	printf("%d",ans);
	return 0;
	
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/84403112