ZCMU 1402 二分匹配(最小点覆盖)

题目链接

题意:n个点,n-1条边组成一颗有根树,求这颗树的最小点覆盖。

思路:抛开树这个模型,将所有点置于二分图的两边,所有边都双向连接之后,做二分图最大匹配并将结果除于2就是答案。因为数据范围较大,所以需要使用Hopcroft_karp算法求解二分图最大匹配,使用匈牙利算法会被卡TLE。

C++代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1510;
const int inf  = 0x3f3f3f3f;
  
int tol;
int head[maxn];
struct edge
{
    int to,next;
}es[maxn<<1];
  
void init()
{
    tol = 0; memset ( head , -1 , sizeof(head) );
}
  
void addedge( int u , int v )
{
    es[tol].to =  v;
    es[tol].next = head[u];
    head[u] = tol++;
}
  
int n,m,dis;
int Mx[maxn],My[maxn];
int dx[maxn],dy[maxn];
bool used[maxn];
  
bool SearchP()
{
    dis = inf; queue<int>Q;
    memset ( dx , -1 , sizeof(dx) );
    memset ( dy , -1 , sizeof(dy) );
    for ( int i=1 ; i<=n ; i++ )
    {
        if ( Mx[i]==-1 )
        {
            dx[i] = 0;
            Q.push(i);
        }
    }
    while ( !Q.empty() )
    {
        int u = Q.front(); Q.pop();
        if ( dx[u]>dis ) break;
        for ( int i=head[u] ; i!=-1 ; i=es[i].next )
        {
            int v = es[i].to;
            if ( dy[v]==-1 )
            {
                dy[v] = dx[u]+1;
                if ( My[v]==-1 )
                {
                    dis = dy[v];
                }
                else
                {
                    dx[My[v]] = dy[v]+1;
                    Q.push(My[v]);
                }
            }
        }
    }
    return dis!=inf;
}
  
bool dfs( int u )
{
    for ( int i=head[u] ; i!=-1 ; i=es[i].next )
    {
        int v = es[i].to;
        if ( !used[v]&&dy[v]==dx[u]+1 )
        {
            used[v] = true;
            if ( My[v]!=-1&&dy[v]==dis ) continue;
            if ( My[v]==-1||dfs(My[v]) )
            {
                My[v] = u;
                Mx[u] = v;
                return true;
            }
        }
    }
    return false;
}
  
int Hopcroft_karp()
{
    int res = 0;
    memset ( Mx , -1 , sizeof(Mx) );
    memset ( My , -1 , sizeof(My) );
    while ( SearchP() )
    {
        memset ( used , false , sizeof(used) );
        for ( int i=1 ; i<=n ; i++ )
            if ( Mx[i]==-1&&dfs(i) ) res++;
    }
    return res>>1;
}
  
int main()
{
    while ( scanf ( "%d%d" , &n , &m )==2 )
    {
        init();
        for ( int i=1 ; i<n ; i++ )
        {
            int u,v; scanf ( "%d%d" , &u , &v );
            addedge ( u+1 , v+1 );
            addedge ( v+1 , u+1 );
        }
        printf ( "%d\n" , Hopcroft_karp() );
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/Game_Acm/article/details/80217212