顾名思义,二分图就是能将图分为两部分的图。这两部分满足只有不同部分间有边,同一部分内没边。这样的图存在许多优美的性质。然后大概就是下一次模拟赛再遇到二分图就不能拿没学过背锅了。
判定
直接定义法,DFS/BFS尝试给图染色。要求相邻点色不同。如果无法达到这种状态说明该图不是二分图。
模型
这里只着重讲讲匹配。匹配是很重要的算法。然后大概就是十分重要了。
匹配问题的根本是最大匹配。定义大概就是每个点只能连一条边,求最多能连多少条边。方法是匈牙利算法。思想就是钦定从一边开始匹配,每次寻找增广路,如果遇到一个另一边的点没有被匹配过或者当前另一边点的匹配点还能找到匹配点,就用该点与另一边点匹配。然后就能保证能匹配的都匹配了。时间复杂度是\(O(n^2)\) 的。
模板代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=510,maxm=5e4+10;
int n,m,e;
int tot,to[maxm],nxt[maxm],h[maxn];
inline void adde(int x,int y){to[++tot]=y;nxt[tot]=h[x];h[x]=tot;
}
bool vis[maxn];
int match[maxn];
inline bool Find(int x){for(int i=h[x];i;i=nxt[i]){int y=to[i];if(!vis[y]){vis[y]=1;if(!match[y]||Find(match[y])){match[y]=x;return 1;}}}return 0;
}
int ans;
inline void hungary(){for(int i=1;i<=n;i++){memset(vis,0,sizeof(vis));if(Find(i)) ++ans;}
}
int main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>m>>e;for(int i=1,u,v;i<=e;i++){cin>>u>>v;adde(u,v);}hungary();cout<<ans;return 0;
}
然后有以下几点性质:
1.最小点覆盖集的大小等于最大匹配集的大小。说通俗点就是选择最少数量的点,使得每条边都有某个端点被选。
2.最大独立集=图的点数-最大匹配。说通俗点就是找出最大的集合内任意两点都没有边相连的集合。
3.最小路径覆盖数=原点数-拆点后的最大匹配。说通俗点就是求最少的路径,使所有的点都在路径上。拆点就是将每个节点拆成入点和出点。
然后二分图跟网络流比较相似的一点就是需要巧妙地建出图,然后剩下的东西一般就比较板了。然后确实一定数量的二分图的题可以用网络流做。但大部分情况下二分图时间复杂度更优。
(最大权匹配先鸽了)