原文地址
========
对于任意图:
|最小边覆盖|+|最大匹配|=|V|
二分图的最大匹配=最小点覆盖数
对于二分图:
以下数值等价.
最大匹配
最小点覆盖
|V|-最大独立集(二分图or有向无环图)
|V|-最小边覆盖数
|V|-最小路径覆盖数(有向无环图)
|V|-最小路径覆盖数/2(无向图)
(上面括号里有有向无环图的,均是将一个点拆成两个点连边匹配)
由于任意图的那几个几乎用不到于是这里只贴二分图的定义
最小点覆盖:理解为点覆盖边,即用最小的点覆盖所有的边。(若一条边的其中一个端点被选用,这条边就被覆盖了)
最大独立集:求一个最大的点集,里面的点不存在任何的边相连。
最小边覆盖:理解为边覆盖点,用最少的边把图中的点全部覆盖。
最小路径覆盖:用最少的路径把图中的所有点覆盖。
另外:最大独立集与最小覆盖集互补。
推广到有权的形式也一样,即最大点权独立集与最小点权覆盖集互补
求最小点权覆盖集可以这样求:
先对图黑白染色,然后向白色的点放X部,黑色的点放Y部。
1、连边[S,i],容量等于i的点权。(对于二分图的X集)
2、连边[i,T],容量等于i的点权。(对于二分图的Y集)
3、对于有边的i和j连边[i,j](i∈X,j∈Y),容量为INF
最后得出的最大流就是最小点权覆盖,实际上是最小割与之对应。
对于求了传递闭包以后的有向无环图:
最大反链=|V|-最大匹配
1 #include <stdio.h>
2
3 #include <
string.h>
4
5
int n1, n2, m, ans;
6
7
int result[
101];
//
记录V2中的点匹配的点的编号
8
bool state [
101];
//
记录V2中的每个点是否被搜索过
9
bool data[
101][
101];
//
邻接矩阵 true代表有边相连
10
void init()
11
12 {
13
14
int t1, t2;
15
16 memset(data,
0,
sizeof(data));
17
18 memset(result,
0,
sizeof(result));
19
20 ans =
0;
21
22 scanf(
"
%d%d%d
", &n1, &n2, &m);
23
24
for (
int i =
1; i <= m; i++)
25
26 {
27
28 scanf(
"
%d%d
", &t1, &t2);k
29
30 data[t1][t2] =
true;
31
32 }
33
34
return;
35
36 }
37
38
bool find(
int a)
39
40 {
41
42
for (
int i =
1; i <= n2; i++)
43
44 {
45
46
if (data[a][i] ==
1 && !state[i])
//
如果节点i与a相邻并且未被查找过
47
{
48
49 state[i] =
true;
//
标记i为已查找过
50
if (result[i] ==
0
//
如果i未在前一个匹配M中
51
|| find(result[i]))
//
i在匹配M中,但是从与i相邻的节点出发可以有增广路
52
{
53
54 result[i] = a;
//
记录查找成功记录
55
return
true;
//
返回查找成功
56
}
57
58 }
59
60 }
61
62
return
false;
63
64 }
65
66
int main()
67
68 {
69
70 init();
71
72
for (
int i =
1; i <= n1; i++)
73
74 {
75
76 memset(state,
0,
sizeof(state));
//
清空上次搜索时的标记
77
if (find(i)) ans++;
//
从节点i尝试扩展(每一次增加一条边 或一个顶点)
78
}
79
80 printf(
"
%d\n
", ans);
81
82
return
0;
83
84 }
邻接表:
1 #include<cstdio>
2 #include<cstring>
3 #include<cmath>
4 #include<iostream>
5 #include<algorithm>
6 #include<
set>
7 #include<map>
8 #include<queue>
9 #include<vector>
10 #include<
string>
11
#define Min(a,b) a<b?a:b
12
#define Max(a,b) a>b?a:b
13
#define CL(a,num) memset(a,num,sizeof(a));
14
#define eps 1e-6
15
#define inf 10001000
16
17
#define ll __int64
18
19
#define read() freopen("data.txt","r",stdin) ;
20
const
double pi = acos(-
1.0);
21
const
int maxn =
200;
22
23
using
namespace std;
24
int n,m;
25
int head[maxn] ;
26
int result[maxn],vis[maxn] ;
27
struct node
28 {
29
int v;
30
int next;
31 }p[maxn*maxn];
32
int cnt ;
33
void add(
int u,
int v)
34 {
35 p[cnt].v = v;
36 p[cnt].next = head[u];
37 head[u] = cnt++ ;
38 }
39
bool find(
int u)
40 {
41
42
for(
int i = head[u];i!= -
1;i = p[i].next)
43 {
44
int v = p[i].v ;
45
if(!vis[v])
46 {
47 vis[v] =
1 ;
48
if(result[v] == -
1||find(result[v]))
49 {
50 result[v] = u;
51
return
true;
52 }
53 }
54 }
55
return
false ;
56 }
57
int
get()
58 {
59
int ans=
0;
60 CL(result,-
1);
61
for(
int i =
1;i <= n;i++)
62 {
63 CL(vis,
0);
64
if(find(i))ans++;
65 }
66
return ans ;
67 }
68
int main()
69 {
70
//
read() ;
71
int t ,i,x,y;
72 scanf(
"
%d
",&t);
73
while(t--)
74 {
75 cnt =
0;
76 CL(head,-
1) ;
77 scanf(
"
%d%d
",&n,&m);
78
for(i =
0 ; i < m;i++)
79 {
80 scanf(
"
%d%d
",&x,&y);
81 add(x,y);
82 }
83
int ans =
get() ;
84 printf(
"
%d\n
",n - ans) ;
85 }
86 }