二分图

判定

变量

  • bool is2f\texttt{bool is2f}:标记是否是二分图。
  • int v[i]\texttt{int v[i]}:标记节点 ii 的颜色。

函数

  • Bipartite_Graph()\texttt{Bipartite\_Graph()}:初始化。
  • void dfs(int x,int col)\texttt{void dfs(int x,int col)}:将节点 xx 的颜色染为 colcol,并给其他没染色的点染色。
  • bool calc()\texttt{bool calc()}:判断 GG 是否是二分图。

代码

struct Bipartite_Graph{
	bool is2f;
	int v[N];
	Bipartite_Graph(){
		is2f=1;
		memset(v,0,sizeof(v));
	}
	void dfs(int x,int col){
		if(!is2f)
			return;
		v[x]=col;
		for(int i=G.head[x];i;i=G.nxt[i]){
			int y=G.ver[i];
			if(v[y]==0)
				dfs(y,3-col);
			else if(v[y]==col){
				is2f=0;
				return;
			}
		}
	}
	bool calc(){
		for(int i=1;i<=n;i++)
			if(!v[i]&&is2f)
				dfs(i,1);
		return is2f;
	}
}tu;

最大匹配

变量

  • int v[i]\texttt{int v[i]}:标记节点 ii 所在的增广路的起点。
  • int match[i]\texttt{int match[i]}:标记节点 ii 配对的点。

函数

  • bool dfs(int x,int tag)\texttt{bool dfs(int x,int tag)}:求现在再找一条从节点 xx 开始,起点为 tagtag 的增广路是否可行。
  • int ask_max(int n)\texttt{int ask\_max(int n)}:求左部有 nn 个节点的最大匹配。

代码

struct Bipartite_Graph{
	int v[N];
	int match[N];
	bool dfs(int x,int tag){
		if(v[x]==tag)
			return 0;
		v[x]=tag;
		for(int i=G.head[x];i;i=G.nxt[i]){
			int y=G.ver[i];
			if(!match[y]||dfs(match[y],tag)){
				match[y]=x;
				return 1;
			}
		}
		return 0;
	}
	int ask_max(int n){
		int ans=0;
		memset(v,0,sizeof(v));
		memset(match,0,sizeof(match));
		for(int i=1;i<=n;i++)
			if(dfs(i,i))
				ans++;
		return ans;
	}
}tu;

最大权匹配

变量

  • const long long INF\texttt{const long long INF}:极大值,不会有一条边的绝对值超过它。
  • int n\texttt{int n}:右部节点的个数,要保证左部节点的个数一定比右部的少。
  • int pre[i]\texttt{int pre[i]}:搜索树上一条非匹配边 pre[i]i\texttt{pre[i]}\leftarrow \texttt{i},其中 ii 是右部点。
  • int matcha[i]\texttt{int matcha[i]}:搜索树上一条匹配边 imatcha[i]\texttt{i}\rightarrow\texttt{matcha[i]},其中 ii 是左部点。
  • int matchb[i]\texttt{int matchb[i]}:搜索树上一条匹配边 matchb[i]i\texttt{matchb[i]}\rightarrow \texttt{i},其中 ii 是右部点。
  • int va[i]\texttt{int va[i]}:左部点 ii 是否被访问过。
  • int vb[i]\texttt{int vb[i]}:右部点 ii 是否被访问过。
  • long long w[i][j]\texttt{long long w[i][j]}:边 iji\rightarrow j 的权值,不存在则为 -INF\texttt{-INF}
  • long long la[i]\texttt{long long la[i]}:左部点 ii 的可行顶标。
  • long long lb[i]\texttt{long long lb[i]}:右部点 ii 的可行顶标。
  • long long slack[i]\texttt{long long slack[i]}:右部点 ii 的松弛值,即 maxj{la[j]+lb[i]-w[j][i]}\max_j\{\texttt{la[j]+lb[i]-w[j][i]}\}
  • long long delta\texttt{long long delta}:可行顶标可变化的最大值。
  • queue<int>q\texttt{queue<int>q}:队列。

函数

  • void init()\texttt{void init()}:初始化边权。
  • void bfs(int s)\texttt{void bfs(int s)}:以 ss 为起点进行 bfs\text{bfs}
  • ll km()\texttt{ll km()}:计算二分图最大权匹配。

代码

struct Bipartite_Graph_Perfect_Matching{
	const long long INF=(1ll<<60);
	int n,pre[N],matcha[N],matchb[N];
	bool va[N],vb[N];
	ll w[N][N],la[N],lb[N],slack[N],delta;
	queue<int>q;
	void init(){
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				w[i][j]=-INF;
	}
	void bfs(int s){
		memset(va,0,sizeof(va));
		memset(vb,0,sizeof(vb));
		for(int i=1;i<=n;i++)
			slack[i]=INF;
		while(q.size())
			q.pop();
		q.push(s);
		while(1){
			while(q.size()){
				int x=q.front();
				q.pop();
				va[x]=1;
				for(int y=1;y<=n;y++)
					if(!vb[y])
						if(la[x]+lb[y]-w[x][y]<slack[y]){
							slack[y]=la[x]+lb[y]-w[x][y];
							pre[y]=x;
							if(!slack[y]){
								vb[y]=1;
								if(!matchb[y]){
									int z=y;
									while(z){
										matchb[z]=pre[z];
										swap(matcha[pre[z]],z);
									}
									return;
								}
								else
									q.push(matchb[y]);
							}
						}
			}
			delta=INF;
			for(int i=1;i<=n;i++)
				if(!vb[i])
					delta=min(delta,slack[i]);
			for(int i=1;i<=n;i++){
				if(va[i])
					la[i]-=delta;
				if(vb[i])
					lb[i]+=delta;
				else
					slack[i]-=delta;
			}
			for(int y=1;y<=n;y++){
				if(!vb[y])
					if(!slack[y]){
						vb[y]=1;
						if(!matchb[y]){
							int z=y;
							while(z){
								matchb[z]=pre[z];
								swap(matcha[pre[z]],z);
							}
							return;
						}
						else
							q.push(matchb[y]);
					}
			}
		}
	}
	ll km(){
		memset(matcha,0,sizeof(matcha));
		memset(matchb,0,sizeof(matchb));
		for(int i=1;i<=n;i++){
			la[i]=-INF;
			lb[i]=0;
			for(int j=1;j<=n;j++)
				la[i]=max(la[i],w[i][j]);
		}
		for(int i=1;i<=n;i++)
			bfs(i);
		ll ans=0;
		for(int i=1;i<=n;i++)
			ans+=w[matchb[i]][i];
		return ans;
	}
}bg;
posted @ 2022-09-21 13:46  luckydrawbox  阅读(9)  评论(0)    收藏  举报  来源