首页 > 代码库 > ACM -二分图题目小结(更新中)

ACM -二分图题目小结(更新中)

暂时只包括与最大匹配相关的问题。

求最大独立集,最小路径覆盖等等大多数题目都可以转化为求最大匹配用匈牙利算法解决。

 

1.最大匹配(边集)

此类问题最直接,直接用匈牙利算法即可。

 HDU 2063  过山车

http://acm.hdu.edu.cn/showproblem.php?pid=2063

二分图最大匹配模版题。

ZOJ 1654 - Place the Robots

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1654

易想到求最大独立集但是时间复杂度太高,可以变成二分图最大匹配来做,重在建模。

 

2.最小路径覆盖(边集)

对于不存在孤立的点的图,|最小路径覆盖|+|最大匹配|=V(顶点数)

因此可以通过求最大匹配来做。

这个等式在DAG图中也成立,详见http://www.cnblogs.com/jackiesteed/articles/2043934.html。对于DAG图可以拆点来做。

HDU 1151 Air Raid

http://acm.hdu.edu.cn/showproblem.php?pid=1151

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstdlib>
 6 #include<cstdio>
 7 #include<vector>
 8 #define MAXN 1005
 9 using namespace std;
10 bool gl[MAXN][MAXN];
11 int link[MAXN];
12 int n;
13 bool vis[MAXN];
14 
15 bool match(int x)
16 {
17     for(int i=1; i<=n; ++i)
18         if(gl[x][i]&&!vis[i])
19         {
20             vis[i]=true;
21             if(link[i]==-1||match(link[i]))
22             {
23                 link[i]=x;
24                 return true;
25             }
26         }
27     return false;
28 }
29 int main()
30 {
31     int T;
32     scanf("%d",&T);
33     while(T--)
34     {  int m;
35         scanf("%d%d",&n,&m);
36         memset(gl,0,sizeof(gl));
37         for(int i=0;i<m;++i)
38         {
39             int x,y;
40             scanf("%d%d",&x,&y);
41             gl[x][y]=true;
42         }
43         int res=0;
44         memset(link,-1,sizeof(link));
45         for(int i=1; i<=n; ++i)
46         {
47             memset(vis,0,sizeof(vis));
48             if(match(i)) res++;
49         }
50         printf("%d\n",n-res);
51     }
52     return 0;
53 }
View Code

求DAG的最小路径覆盖。

 

3.最小顶点覆盖(点集)

在二分图中|最大匹配|=|最小顶点覆盖|,但是注意要解决的问题本身并不是最大匹配,理解了问题本身才能建模。

HDU 1054  Strategic Game

http://acm.hdu.edu.cn/showproblem.php?pid=1054

此题可以用树形DP来做也可以用求最小顶点覆盖,但是时间较慢。拆点,改成双向图,用邻接表。

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<vector>
#define MAXN 1505
using namespace std;
vector<int> gl[MAXN];
int link[MAXN];
int n;
bool vis[MAXN];
void init()
{
    memset(link,-1,sizeof(link));
    memset(vis,0,sizeof(vis));
}

bool match(int x)
{
    for(int i=0; i<gl[x].size(); ++i)
    {
        int &u=gl[x][i];
        if(!vis[u])
        {
            vis[u]=true;
            if(link[u]==-1||match(link[u]))
            {
                link[u]=x;
                return true;
            }
        }
    }

    return false;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(gl,0,sizeof(gl));
        for(int i=0; i<n; ++i)  gl[i].clear();
        for(int i=0; i<n; ++i)
        {
            int now,t,cn;
            scanf("%d:",&now);
            scanf("(%d)",&cn);
            while(cn--)
            {
                scanf("%d",&t);
                gl[now].push_back(t);
                gl[t].push_back(now);
            }
        }
        init();
        int res=0;
        for(int i=0; i<n; ++i)
        {
            memset(vis,0,sizeof(vis));
            if(match(i)) res++;
        }
        printf("%d\n",res/2);
    }
    return 0;
}
View Code

HDU 1150  Machine Schedule

http://acm.hdu.edu.cn/showproblem.php?pid=1150

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<vector>
#define MAXN 1005
using namespace std;
bool gl[MAXN][MAXN];
int link[MAXN];
int n,m;
bool vis[MAXN];

bool match(int x)
{
    for(int i=1; i<=m; ++i)
        if(gl[x][i]&&!vis[i])
        {
            vis[i]=true;
            if(link[i]==-1||match(link[i]))
            {
                link[i]=x;
                return true;
            }
        }
    return false;
}
int main()
{
    int t;
    while(scanf("%d",&n)&&n)
    {
        scanf("%d%d",&m,&t);
        memset(gl,0,sizeof(gl));
        for(int i=0; i<t; ++i)
        {
            int x,y,z;
            scanf("%d%d%d",&z,&x,&y);
            gl[x][y]=true;
        }
        int res=0;
        memset(link,-1,sizeof(link));
        for(int i=1; i<=n; ++i)
        {
            memset(vis,0,sizeof(vis));
            if(match(i)) res++;
        }
        printf("%d\n",res);
    }
    return 0;
}
View Code

 


4.最大独立集(点集)

|最大独立集|+|最小顶点覆盖|=V

求最大独立集是NP问题,但是在二分图中|最大匹配|=|最小顶点覆盖|,所以这个问题也有了高效的算法。

 HDU 1045  Fire Net

http://acm.hdu.edu.cn/showproblem.php?pid=1045

这个可以暴力求最大独立集。

HDU 2768  Cat vs. Dog

http://acm.hdu.edu.cn/showproblem.php?pid=2768

根据矛盾之间建图,求最大独立集。

HDU 1068  Girls and Boys

http://acm.hdu.edu.cn/showproblem.php?pid=1068

题意很明显就是求二分图最大独立集。但是由于没说给的是男还是女,所以需要拆点,得到的最大匹配数要除以2,再套用公式得最大独立集。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstdlib>
 6 #include<cstdio>
 7 #include<vector>
 8 #define MAXN 1005
 9 using namespace std;
10 bool gl[MAXN][MAXN];
11 int link[MAXN];
12 int n;
13 bool vis[MAXN];
14 void init()
15 {
16     memset(link,-1,sizeof(link));
17     memset(vis,0,sizeof(vis));
18 }
19 
20 bool match(int x)
21 {
22     for(int i=0; i<n; ++i)
23         if(gl[x][i]&&!vis[i])
24         {
25             vis[i]=true;
26             if(link[i]==-1||match(link[i]))
27             {
28                 link[i]=x;
29                 return true;
30             }
31         }
32     return false;
33 }
34 int main()
35 {
36     while(scanf("%d",&n)!=EOF)
37     {
38         memset(gl,0,sizeof(gl));
39         for(int i=0; i<n; ++i)
40         {
41             int now,t,cn;
42             scanf("%d: ",&now);
43             scanf("(%d) ",&cn);
44             while(cn--)
45             {
46                 scanf("%d",&t);
47                 gl[now][t]=true;
48             }
49         }
50         init();
51         int res=0;
52         for(int i=0; i<n; ++i)
53         {
54             memset(vis,0,sizeof(vis));
55             if(match(i)) res++;
56         }
57         printf("%d\n",(n*2-res)/2);
58     }
59     return 0;
60 }
View Code

 

 

5.判断二分图

此类问题可以BFS或DFS解决,注意图可能不连通。

 HDU 4751 Divide Groups

http://acm.hdu.edu.cn/showproblem.php?pid=4751

根据不互相认识这一关系连边,判断二分图。