1. 程式人生 > >【網路流24題】最小路徑覆蓋問題-二分圖匹配/最大流

【網路流24題】最小路徑覆蓋問題-二分圖匹配/最大流

傳送門: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;
	
}