2 solutions
-
1
#include<bits/stdc++.h> using namespace std; const int N=110; int n,m,k; int match[N]; bool g[N][N],st[N]; bool find(int x) { for(int i=1;i<m;i++) { if(!i[st]&&i[x[g]]) { i[st]=true; if(i[match]==0||find(i[match])) { i[match]=x; return true; } } } return false; } int main() { while(cin>>n,n) { cin>>m>>k; memset(g,false,sizeof g); memset(match,0,sizeof match); while(k--) { int t,a,b; cin>>t>>a>>b; if(a&&b) { b[a[g]]=true; } } int res=0; for(int i=1;i<n;i++) { memset(st,false,sizeof st); if(find(i)) { res++; } } cout<<res<<"\n"; } return 0; } -
1
Konig定理
二分图最小点覆盖包含的点数等于二分图最大匹配包含的边数。
证明:
因为最大匹配是原二分图边集的一个子集,并且所有的边都不相交,所以需要从每条匹配边中选出一个端点。因此,最小点覆盖包含的点数不可能小于最大匹配包含的边数。如果能对任意二分图构造出一组点覆盖,其包含的点数等于最大匹配包含的边数那么定理就能得证。
构造方法:
1.求出二分图最大匹配
2.从左部每个非匹配点出发,再执行一次DFS寻找增广路的过程(一定会失败),标记访问过的节点
3.取左部未被标记的点、右部被标记的点,就得到了二分图的最小点覆盖
下面证明该构造的正确性。
经过上述构造方法后:
左部非匹配点一定都被标记--因为它们是出发点
右部非匹配点一定都没被标记--否则就找到了增广路
一对匹配点要么都被标记,要么都没被标记--因为在寻找增广路的过程中,左部匹配点只能通过右部到达。
在构造中,我们取了左部未被标记的点,右部被标记的点。根据上面的讨论可以发现,恰好是每条匹配边取了一个点,所以选出的点数等于最大匹配包含的边数。
再来讨论这种取法是否覆盖了所有的边:
匹配边一定被覆盖--因为恰好有一个端点被取走
不存在连接两个非匹配点的边--否则就有长度为1的增广路了
连接左部非匹配点i,右部匹配点j的边--因为i是出发点,所以j一定被访问。而我们取了右部所有被标记的点,因此这样的边也被覆盖。
连接左部匹配点i,右部非匹配点j的边--i一定没有被访问,否则再走到j就找到了增广路。而我们取了左部所有未被标记的点,因此这样的边也被覆盖。
- 1
Information
- ID
- 354
- Time
- 1000ms
- Memory
- 128MiB
- Difficulty
- 10
- Tags
- # Submissions
- 8
- Accepted
- 5
- Uploaded By