AcWing 算法提高课 二分图

1、性质:二分图,等价于不存在奇数环、用染色法染色没有矛盾。

 染色法求二分图模板:

int n,m;
const int N=20010;
vector<int> adj[N];
vector<int> cost[N];
int color[N];//0表示未染色,1白色,2黑色

bool DFS(int u,int c)
{
    color[u]=c;
    for(int i=0;i<adj[u].size();i++)
    {
        int nxt=adj[u][i];
        int w=cost[u][i];
        
        if(color[nxt])
        {
            if(color[nxt]==c) return false;
        }
        else
        {
            if(!DFS(nxt,3-c)) return false;
        }
    }
    return true;
}
bool Check()
{
    memset(color,0,sizeof(color));
    fore(i,1,n)
    {
        if(color[i]==0)
        {
            if(!DFS(i,1))
                return false;
        }
    }
    return true;
}
void YD()
{
    cin>>n>>m;
    while(m--)
    {
        int a,b,c;cin>>a>>b>>c;
        adj[a].pub(b);
        cost[a].pub(c);
        adj[b].pub(a);
        cost[b].pub(c);
    }

    Check();

}
View Code

 2、匈牙利算法求二分图中的最大匹配

 

匹配:取出来的边,没有公共点,类似找对象,一夫一妻

增广路径:非匹配点开始,走非匹配边和匹配边交替的路径,最后到非匹配点。

 

可以发现增广路径可以构造出更大的匹配。

最大匹配等价于无增广路径。

匈牙利算法可以在二分图中求出最大匹配

匈牙利算法的本质就是图的深度优先遍历,

思想为,找对象:假设二分图一边全是女生,另一边全是男生,给全部的男生找对象,如果可以找到一个女生没有对象则直接找到,

否则就看能不能将女生的对象分给别的女生,如果能,就将其对象更改,并把女生与当前男生进行匹配。

例题:https://www.acwing.com/problem/content/374/

其中 find函数是匈牙利算法的核心

模板:

const int N = 110;
int n, m, k;
vector<int> adj[N];
bool st[N];
int match[N];
bool Find(int x)
{
    for (auto nxt : adj[x])
    {
        if (!st[nxt])
        {
            st[nxt] = true;
            int t = match[nxt];
            if (t == 0 || Find(t))
            {
                match[nxt] = x;
                return true;
            }
        }
    }
    return false;
}
void YD()
{
    cin >>n>> m >> k;

    memset(match, 0, sizeof(match));
    fore(i,1,n) adj[i].clear();
    while (k--)
    {
        int a, b; cin >> a >> b;
        adj[a].push_back(b);
    }
    int res = 0;
    fore(i, 1, n)
    {
        memset(st, 0, sizeof(st));
        if (Find(i)) res++;
    }
    cout << res << endl;
}
View Code

注意,集合A中有n个点,集合B中有m个点,adj是A中点向B中点连接的边,match和st是B中点的匹配或state

3、以下性质(二分图)

(1)点覆盖:任意一边至少有一个点被选中。

在二分图中,最小点覆盖等于最大匹配数。

最小点覆盖例题:https://www.acwing.com/problem/content/378/

 

(2)最大独立集:选出最多的点使得选出的点之间没有边。

最大团:选出最多的点使得选出的点中任意两点之间都有边。

原图的最大独立集就是补图的最大团

在二分图中(!),求最大独立集,等价于去掉最少的点将所有边都破坏掉,即找到最小点覆盖并去掉,即找到最大匹配数并去掉。 

最大独立集例题:https://www.acwing.com/problem/content/380/

 

(3)最小路径点覆盖:对于DAG(有向无环图),用最少的互不相交(点不重复)的路径覆盖全部点。

解决方法:

(1)拆点,将点分为入点和出点,边变为由出点指向入点,此时原图可转化为二分图

 

 

此时答案为n-m,其中m为二分图的最大匹配数。

思路:

(1)原图中的每条路径,都对应着二分图中的一个匹配(因为路径不会分叉,二分图中每个点度最多为1)

(2)路径的终点没有出边,对应着左侧的非匹配点,又因为所有点都会被覆盖,所以左侧的非匹配点都对应着一条路径的终点

(3)求原图中的最小路径覆盖,等价于求二分图中,左侧的最少非匹配点数量,即点数n-最大匹配数m

 

 

(4)最小路径重复点覆盖:对于DAG,用最少的(点和边可重的)路径覆盖全部点。

方法:

(1)先求原图的传递闭包

(2)原图的最小路径重复点覆盖等价于传递闭包的最小路径点覆盖

(3)可以证明二者中的路径一一对应

(4)转化为求二分图中最大匹配数问题

例题:https://www.acwing.com/problem/content/381/

posted @ 2022-09-20 17:00  80k  阅读(34)  评论(0编辑  收藏  举报