二分图最大匹配算法

/*
该模板不用建立超级源点和超级汇点,
直接把二分图中对应的边连接即可
*/
int V;//顶点数
vector<int> G[N];//图的邻接表表示
int match[N];//所匹配的点顶点
bool used[N];//dfs中用到的访问标志
//向图中增加一条连接u和v的边
void addedge(int u,int v)
{
    G[u].push_back(v);
    G[v].push_back(u);
}
//通过dfs寻找增广路径
bool dfs(int v)
{
    used[v]=true;
    for(int i=0;i<G[v].size();i++)
    {
        int u=G[v][i];
        int w=match[u];
        if(w<0||!used[w]&&dfs(w))
        {
            match[v]=u;
            match[u]=v;
            return true;
        }
    }
    return false;
}
//求解二分图的最大匹配
int bipartite_matching()
{
    int ans=0;
    memset(match,-1,sizeof(match));
    for(int v=0;v<V;v++)
    {
        if(match[v]<0)
        {
            memset(used,0,sizeof(used));
            if(dfs(v))
                ans++;
        }
    }
    return ans;
}
/*
该模板是基于最大流算法的,
因此需要建立超级源点和超级汇点
*/
struct edge
{
    int to,cap,rev;//终点,容量,反向边
};
vector<edge>G[N];//图的邻接矩阵表示
bool used[N];//dfs中用到的访问标记
int can[N][N];//存原始图,c[i][j]=1表示i到j可达
int n,m;//左点集的个数和右点集的个数
int s,t;//超级源点和超级汇点
void addedge(int u,int v,int w)
{
    G[u].push_back((edge){v,w,G[v].size()});
    G[v].push_back((edge){u,0,G[u].size()-1});
}
int dfs(int v,int t,int f)
{
    if(v==t)
        return f;
    used[v]=true;
    for(int i=0;i<G[v].size();i++)
    {
        edge &e=G[v][i];
        if(!used[e.to]&&e.cap>0)
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
//求解从s到t上的最大流
int max_flow(int s,int t)
{
    int flow=0;
    for(;;)
    {
        memset(used,0,sizeof(used));
        int f=dfs(s,t,INF);
        if(f==0)
            return flow;
        flow+=f;
    }
}
//建图
void Get_map()
{
    s=0,t=m+1;//按实际情况确定s和t
    //超级源点向左点集连边
    for(int i=1;i<=n;i++)
        addedge(s,i,1);
    //右点集向超级汇点连边
    for(int i=n+1;i<=m;i++)
        addedge(i,t,1);
    //左点集向右点集连边
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=m;j++)
            if(can[i][j])
               addedge(i,j,1);
    }
}

有向无环图(DAG)的最小路径覆盖
有向无环图中,路径覆盖就是在图中找一些路径,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次)。最小路径覆盖就是找出最小的路径条数,使之成为原图的一个路径覆盖。
在《图论及应用》中有这样一张图:
这里写图片描述
由图中可以看出,我们主要把有向无环图中每个顶点都拆成两个,然后在连上对应的边,那么所求问题就可以转化为:
最小路径覆盖=(原图)顶点数-对应的二分图的最大匹配数
把图转化后,套用二分图匹配模板即可求解(注意:转化后顶点数要乘2,求解最终答案时要除2)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值