POJ 3041 - 最大二分匹配

这道题实现起来还是比较简单的,但是理解起来可能有点困难。

我最开始想到的是贪心法,每次消灭当前小行星最多的一行或一列。然而WA了。Discuss区里已经有高人给出反例。

下面给出正确的解法

我们把行和列抽象成点,把小行星抽象成边,每出现一个小行星,就把其行列所对应的点连起来。这样就形成了一个无向图$G=\left(V, E\right)$。问题就转化为了求这个图G中的最小点覆盖,即求一个元素数量尽可能小的点集$V‘ \subset V$,$E$中的所有边均与其内的一点相连。

最小点覆盖问题是一个NP困难问题,目前没有已知的能够在多项式时间内解决该问题的算法。

不过我们可以这样考虑:

我们给出一个定义:设存在一个集合${V}_{1} \subset V, ~ {V}_{2} = V - {V}_{1}$。若$a \in {V}_{1}, ~ b \in {V}_{2}, ~ (a, b) \in E$,那么我们称这条边$(a, b)$为一个匹配。

若有两个点集${V}_{1} \subset V, ~ {V}_{2} = V - {V}_{1}$,两者并不相交。若有一种方案,使得${V}_{1}$和${V}_{2}$的所有匹配之间均没有重复的点,且${V}_{1}$内的所有点均拥有至少一个匹配。则当${V}_{1}$的元素数量最大时,${V}_{1}$就是这张图的最小点覆盖。

我们这里做一个简单的不严谨的证明,便于理解:

  1. ${V}_{1}$的元素数量没有达到最大,意味着至少有一条边,它的两个端点都不在${V}_{1}$中。显然${V}_{1}$不是这张图的一个点覆盖,因为它不符合点覆盖的定义。
  2. 假设${V}_{1}$是这张图的一个点覆盖。如果${V}_{1}$中存在一个点$v$,它在${V}_{2}$中没有满足上述条件的对应点。那么要么没有边与该点相连,要么与其相连的边的另一个端点全在${V}_{1}$内。不论如何,我们都可以把$v$从${V}_{1}$中去掉,其仍然是这张图的一个点覆盖。换句话说,此时的${V}_{1}$并不是最小点覆盖。
  3. 假设${V}_{1}$是这张图的一个点覆盖。${V}_{2} = V - {V}_{1}$。

综上所述,若存在某一条边,其两个点均不在${V}_{1}$中,那么${V}_{1}$就不是这张图的点覆盖。若${V}_{1}$是此图的一个点覆盖,其中存在某个点,它在${V}_{2} = V - {V}_{1}$中没有边与其相连,那么${V}_{1}$不是该图的最小点覆盖。若没有一种方案,使得所有的匹配之间都没有重复的点,那么${V}_{1}$也不是该图的最小点覆盖。

图中的所有点要么在${V}_{1}$中,要么在${V}_{2} = V - {V}_{1}$中。我们每找到一条两点$(a, b)$均不在${V}_{1}$中的边,就将$a$从${V}_{2}$中移入${V}_{1}$,将这条边记作一个匹配。当然,如果有必要,我们也可以将$a$移回${v}_{2}$,再将$b$移进${V}_{1}$;或者将$a$和$b$都移回${V}_{2}$,删除这条匹配。若我们所找到的匹配没有达到最大数量,则意味着还存在有至少一条边,它的两个点均不在${V}_{1}$中。此时的${V}_{1}$并不是这张图的点覆盖。

并且,根据证明3,我们这里所找到的匹配,它们中任意两条之间不能拥有重复的点。

而当我们找到的符合条件的边(也就是匹配)的数量最大时,${V}_{1}$刚好变成了这张图的一个点覆盖,并且,它时这张图的最小点覆盖。

这时,找点的问题被转化成了找边的问题。

在这个具体的问题里,我们所找到的符合条件的边,其两端点必定一个代表行,一个代表列。也就是说,如果我们将$V$划分为代表行的点集${V}_{r}$和代表列的点集${V}_{c}$,则所有的匹配一定是跨越了这两个集合的。

这样,所有的边$(a, b)$不仅是${V}_{1}$、${V}_{2}$之间的匹配,也是${V}_{r}$和${V}_{c}$间的匹配。并且,我们这里所找到的所有的边,它们的点都不重复(否则就违反了刚才的证明3)。因此,找边的问题就变成了找二分匹配的问题。找到的边最大就变成了找到的二分匹配最大。

这个问题就被转化成了一个最大二分匹配问题。

最大二分匹配问题,可以用网络流的手段解决,也可以用匈牙利算法解决。匈牙利算法是一种专门用来解决二分匹配问题的算法,在这里就不具体解释了。不过这道题也是我第一次用这个算法解决问题,错了很多次。

 1 #include <cstddef>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <iostream>
 6
 7 int n, k;
 8
 9 bool dfs_visited[510];
10 int graph[510][510];
11 int matches[510];
12
13 bool Hungarian_Aux(int vertex) {
14
15     for(int i = 1; i <= n; ++i) {
16         if(!graph[vertex][i] || dfs_visited[i])
17             continue;
18         dfs_visited[i] = true;
19         if(matches[i] == 0 || Hungarian_Aux(matches[i])) {
20             matches[i] = vertex;
21             return true;
22         }
23     }
24
25     return false;
26 }
27
28 int Hungarian_Algorithm() {
29     int matches_count = 0;
30     for(int vertex = 1; vertex <= n; ++vertex) {
31         memset(dfs_visited + 1, 0, n * sizeof(bool));
32         if(Hungarian_Aux(vertex)) {
33             ++matches_count;
34         }
35     }
36
37     return matches_count;
38 }
39
40
41 int main() {
42     scanf("%d%d", &n, &k);
43     int r, c;
44     for(int i = 1; i <= k; ++i) {
45         scanf("%d%d", &r, &c);
46         graph[r][c] = true;
47     }
48     printf("%d\n", Hungarian_Algorithm());
49
50     return 0;
51 }
时间: 2024-10-26 07:13:15

POJ 3041 - 最大二分匹配的相关文章

poj 1469 COURSES (二分匹配)

COURSES Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16877   Accepted: 6627 Description Consider a group of N students and P courses. Each student visits zero, one or more than one courses. Your task is to determine whether it is poss

poj COURSES(二分匹配)

题目链接:http://poj.org/problem?id=1469 COURSES Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17135   Accepted: 6730 Description Consider a group of N students and P courses. Each student visits zero, one or more than one courses. Your tas

poj 2446 Chessboard (二分匹配)

Chessboard Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 12800   Accepted: 4000 Description Alice and Bob often play games on chessboard. One day, Alice draws a board with size M * N. She wants Bob to use a lot of cards with size 1 * 2

poj 2226 Muddy Fields(合理建图+二分匹配)

1 /* 2 题意:用木板盖住泥泞的地方,不能盖住草.木板任意长!可以重叠覆盖! '*'表示泥泞的地方,'.'表示草! 3 思路: 4 首先让我们回忆一下HDU 2119 Matrix这一道题,一个矩阵中只有0, 1,然后让我们通过选择一行,或者 5 是一列将其所在行的或者所在列的 1全部删掉,求出最少需要几步? 6 7 这道题的思路就是:将行标 和 列标值为1的建立一条边!通过匈牙利算法可以得到这个二分图的最大匹配数 8 最大匹配数==最小顶点覆盖数!最小顶点覆盖就是用最少的点覆盖了这个二分图

POJ 3014:Asteroids(二分匹配,匈牙利算法)

Asteroids Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14399   Accepted: 7836 Description Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1 <= N <= 500). The grid contains K as

poj 1274 The Perfect Stall (二分匹配)

The Perfect Stall Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17768   Accepted: 8104 Description Farmer John completed his new barn just last week, complete with all the latest milking technology. Unfortunately, due to engineering pr

poj 1422 Air Raid (二分匹配)

Air Raid Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 6520   Accepted: 3877 Description Consider a town where all the streets are one-way and each street leads from one intersection to another. It is also known that starting from an i

POJ 1274 The Perfect Stall、HDU 2063 过山车(最大流做二分匹配)

The Perfect Stall Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24081   Accepted: 10695 Description Farmer John completed his new barn just last week, complete with all the latest milking technology. Unfortunately, due to engineering p

poj 2060 Taxi Cab Scheme (二分匹配)

Taxi Cab Scheme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 5710   Accepted: 2393 Description Running a taxi station is not all that simple. Apart from the obvious demand for a centralised coordination of the cabs in order to pick up