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

我最开始想到的是贪心法,每次消灭当前小行星最多的一行或一列。然而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)。因此,找边的问题就变成了找二分匹配的问题。找到的边最大就变成了找到的二分匹配最大。

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

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

 #include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream> int n, k; bool dfs_visited[];
int graph[][];
int matches[]; bool Hungarian_Aux(int vertex) { for(int i = ; i <= n; ++i) {
if(!graph[vertex][i] || dfs_visited[i])
continue;
dfs_visited[i] = true;
if(matches[i] == || Hungarian_Aux(matches[i])) {
matches[i] = vertex;
return true;
}
} return false;
} int Hungarian_Algorithm() {
int matches_count = ;
for(int vertex = ; vertex <= n; ++vertex) {
memset(dfs_visited + , , n * sizeof(bool));
if(Hungarian_Aux(vertex)) {
++matches_count;
}
} return matches_count;
} int main() {
scanf("%d%d", &n, &k);
int r, c;
for(int i = ; i <= k; ++i) {
scanf("%d%d", &r, &c);
graph[r][c] = true;
}
printf("%d\n", Hungarian_Algorithm()); return ;
}

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

  1. poj 2446 Chessboard (二分匹配)

    Chessboard Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 12800   Accepted: 4000 Descr ...

  2. POJ 3057 Evacuation (二分匹配)

    题意:给定一个图,然后有几个门,每个人要出去,但是每个门每个秒只能出去一个,然后问你最少时间才能全部出去. 析:初一看,应该是像搜索,但是怎么保证每个人出去的时候都不冲突呢,毕竟每个门每次只能出一个人 ...

  3. POJ 2289 多重二分匹配+二分 模板

    题意:在通讯录中有N个人,每个人能可能属于多个group,现要将这些人分组m组,设各组中的最大人数为max,求出该最小的最大值 下面用的是朴素的查找,核心代码find_path复杂度是VE的,不过据说 ...

  4. POJ 3041 Asteroids 二分图匹配

    以行列为点建图,每个点(x,y) 对应一条边连接x,y.二分图的最小点覆盖=最大匹配 //#pragma comment(linker, "/STACK:1024000000,1024000 ...

  5. POJ 1469 ZOJ1140 二分匹配裸题

    很裸,左点阵n,右点阵m 问最大匹配是否为n #include <cstdio> #include <cstring> #include <vector> usin ...

  6. poj 1469 COURSES (二分匹配)

    COURSES Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16877   Accepted: 6627 Descript ...

  7. Guardian of Decency POJ - 2771 【二分匹配,最大独立集】

    Problem DescriptionFrank N. Stein is a very conservative high-school teacher. He wants to take some ...

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

    The Perfect Stall Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24081   Accepted: 106 ...

  9. poj 1247 The Perfect Stall 裸的二分匹配,但可以用最大流来水一下

    The Perfect Stall Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16396   Accepted: 750 ...

随机推荐

  1. 第二节:Series基本属性及方法(下)

  2. Vue 中Bus使用

    使用:兄弟组件之间传值: 安装: npm install vue-bus 在main.js 中引入vuebus: import Vue from 'vue'; import VueBus from ' ...

  3. [Poj1743] [后缀数组论文例题] Musical Theme [后缀数组不可重叠最长重复子串]

    利用后缀数组,先对读入整数处理str[i]=str[i+1]-str[i]+90这样可以避免负数,计算Height数组,二分答案,如果某处H<lim则将H数组分开,最终分成若干块,判断每块中是否 ...

  4. 使用JQUERY的flexselect插件来实现将SELECT下拉菜单变成自动补全输入框

    这也是下拉列表太长了之后,使用的同事提出来的意见, 然后,本来开始想将DJANGO的那个后台下拉菜单移植过来的,但发现不现实,也麻烦, 就找了几个JQUERY的插件测试了一下,最后选中了flexsel ...

  5. nyoj_513_A+B Problem IV_20130131532

    A+B Problem IV 时间限制:1000 ms  |           内存限制:65535 KB 难度:3   描述 acmj最近发现在使用计算器计算高精度的大数加法时很不方便,于是他想着 ...

  6. [bzoj4010][HNOI2015]菜肴制作_贪心_拓扑排序

    菜肴制作 bzoj-4010 HNOI-2015 题目大意:给定一张n个点m条边的有向图,求一个toposort,使得:(1)满足编号为1的点尽量在前:(2)满足(1)的情况下编号为2的点尽量在前,以 ...

  7. [Vue] Code split by route in VueJS

    In this lesson I show how to use webpack to code split based on route in VueJS. Code splitting is a ...

  8. android4.4的两个bug

    Android4.4做了大量的改动.但也造成了非常多新的问题. 工作中碰到了几个比較有趣的bug.这两个bug在nexus 5上也有. 记录一下.以资纪念 1.Android4.4在解析jpg头的时候 ...

  9. LeetCode——Valid Number

    Validate if a given string is numeric. Some examples: "0" => true " 0.1 " =&g ...

  10. 每日算法之二十六:Substring with Concatenation of All Words

    变相的字符串匹配 给定一个字符串,然后再给定一组同样长度的单词列表,要求在字符串中查找满足下面条件的起始位置: 1)从这个位置開始包括单词列表中全部的单词.且每一个单词仅且必须出现一次. 2)在出现的 ...