2 solutions

  • 1
    @ 2026-1-24 19:37:56
    #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
      @ 2024-3-29 13:58:34

      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