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

我最开始想到的是贪心法,每次消灭当前小行星最多的一行或一列。然而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. 3 numpy模块

    Numpy     什么是Numpy:Numeric Python         Numpy模块是Python的一种开源的数值计算扩展.             1 一个强大的N维数组对象Array ...

  2. [bzoj1455]罗马游戏_左偏树_并查集

    罗马游戏 bzoj-1455 题目大意:给你n个人,2种操作,m次操作:1.将i号士兵所在的集合的最小值删除 2.合并i和j两个士兵所在的团体 注释:$1\le n\le 10^6$,$1\le m ...

  3. fixed_date , 赋权技巧 ,procedure执行方式, PL/SQL注意的地方

    本文讨论4个知识点, 1. fixed_date参数 2. 赋权技巧 3. procedure执行的方式 4. PL/SQL中要注意的几个地方 fixed_date参数 客户想修改oracle的 系统 ...

  4. h5 播放器 -3

    autoplay <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  5. 零基础学python-4.2 其它内建类型

    这一章节我们来聊聊其它内建类型 1.类型type 在python2.2的时候,type是通过字符串实现的,再后来才把类型和类统一 我们再次使用上一章节的图片来说明一些问题 我们通过对照上面的图片.在p ...

  6. 分享修改密码的SharePoint Web part: ITaCS Change Password web part

    Codeplex 上有一个现成的修改密码的Web part, 在SharePoint 2010和SharePoint 2013都可以用 项目地址:http://changepassword.codep ...

  7. Mahout算法调用展示平台2.1

    软件版本号: windows7: Tomcat7.JDK7.Spring4.0.2.Struts2.3.Hibernate4.3.myeclipse10.0.easyui:Linux(centos6. ...

  8. 【面试题】Redis相关

    1.Redis与Memorycache的区别? Redis使用单线程,而Memcached是多线程, Redis使用现场申请内存的方式来存储数据,并且可以配置虚拟内存:Memcached使用预分配的内 ...

  9. SQL 优化记录

    1. 对Where 语句的法则 1.1 避免在WHERE子句中使用in,not  in,or 或者having. 可以使用 exist 和not exist代替 in和not in. 可以使用表链接代 ...

  10. Elasticsearch源码分析—线程池(十一) ——就是从队列里处理请求

    Elasticsearch源码分析—线程池(十一) 转自:https://www.felayman.com/articles/2017/11/10/1510291570687.html 线程池 每个节 ...