UVA 11419 SAM I AM(最大二分匹配&最小点覆盖:König定理)
题意:在方格图上打小怪,每次可以清除一整行或一整列的小怪,问最少的步数是多少,又应该在哪些位置操作(对输出顺序没有要求)。
分析:最小覆盖问题
这是一种在方格图上建立的模型:令S集表示“行”,T集表示“列”,那么小怪站的位置w(i,j),就是二分图上的边。如此建图,那么每次清除,就是把与某个点相连的边全部清除,问最少选择多少个点。(这也是最小点覆盖的概念:选择尽量少的点,使得每条边至少有一个端点被选中)
这里有一个König定理:最大二分匹配数==最小覆盖点数。
既然是求最小点覆盖,那么自然是选那些所连边数多的点,不过貌似不好安排啊?
先从简单问题开始讨论:找到必然要选的点。对于一棵树,为了覆盖到叶子节点所在的边,必须选择该条边上的两个端点之一。不用问,按照最小覆盖的原则,必然是要选非叶子节点了。把所有与选择的点相连的边都处理掉,就相当于是这棵树的最下面一层被砍掉了(叶子的爷爷成为了新的叶子)。那么对于剩下的树,仍然可以这样操作,最终得到了最小点覆盖。幸运的是,树属于二分图,而二分图虽然不一定是树(存在偶环),但可以构建出匈牙利树(交错树),是可以借鉴的。
聪明的地球人提出了如下算法:
对于一个二分图,求出其最大匹配。然后取左侧(S侧)所有的未匹配点,按照增广路算法,寻找交错路径(路径上的点都是匹配点),标记掉路径上的所有点(不存在重复标记)。那么左侧(S侧)所有的未标记点,与右侧(T侧)所有的标记点,就是实现最小点覆盖的点。
1、为什么这些点可以覆盖所有边?
如果还有没有覆盖的边,那么一定是一些左端点已标记,右端点未标记的边。而通过我们算法中的构造,不存在这样的边。为什么呢?回忆一下增广路算法,我们的起点选择的是S侧的未匹配点,之后选择一条边走到T侧(该点必然是匹配点);因为要走交错路径,就沿着匹配边回到了S侧...可以想象成每次只是从S侧走到T侧,然后沿匹配边回到S侧。所以不存在S端已标记,T端未标记的线段。所以所有边都被覆盖了。
2、为什么这些点的在数量上等于最大二分匹配的边数?
因为每条匹配边上恰好选择一个点。为什么是这样呢?注意,最小点覆盖的点集包括:S侧的未标记点,和T侧的标记点。有增广路算法可知(同上一个问题相似),若T侧的点被标记,那么同一条匹配边上的S侧的点必然也被标记——点集中不包含同一条匹配边上的两个点。S侧的未标记点,实际上是除去未匹配点,以及跟随T侧点而被标记的点后,剩余的(即选择了那些T侧未被标记的匹配边)。所以两侧的点把所有的匹配边都包含了。所以最大二分匹配数==最小覆盖点数。
3、为什么这些点就是最小值?
这个问题最简单:及使图上只有n条匹配边,我们都要用n个点才能覆盖。若再少,至少漏掉一条匹配边。所以是最小值。
(注:难得自己动手改了张图...圆圈是覆盖点,方格是标记点,箭头是交错路径,蓝线是匹配边。)
可以看看这个链接,我认为上面的解释更通俗一些。
http://www.matrix67.com/blog/?s=%E6%9C%80%E5%B0%8F%E8%A6%86%E7%9B%96%E7%82%B9
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define clr(a,m) memset(a,m,sizeof(a))
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std; const int MAXN=; int n,m,cnt,ans; vector<int>G[MAXN];
vector<int>row,col; int left[MAXN],right[MAXN],S[MAXN],T[MAXN]; void init()
{
rep(i,,n)
G[i].clear();
} void read()
{
int x,y;
init();
rep(i,,cnt){
scanf("%d%d",&x,&y);
G[x].push_back(y);
}
} bool match(int u)
{
S[u]=true;
int sz=G[u].size();
rep(i,,sz-){
int v=G[u][i];
if(!T[v]){
T[v]=true;
if(!left[v]||match(left[v])){
left[v]=u;
right[u]=v;
return true;
}
}
}
return false;
} void AP()
{
rep(i,,m)left[i]=;//n和m写反了
rep(i,,n)right[i]=; ans=;
rep(i,,n){
rep(j,,n)S[j]=;
rep(j,,m)T[j]=;
if(match(i))
ans++;
}
} void mincover()
{
rep(i,,n)S[i]=;//重新标记增广路
rep(i,,m)T[i]=; rep(i,,n)//选择S侧的未标记点
if(!right[i])
match(i); row.clear();
col.clear();
rep(i,,n)
if(!S[i])
row.push_back(i);
rep(i,,m)
if(T[i])
col.push_back(i);
} void print()
{
printf("%d",ans);
int sz=col.size();
rep(i,,sz-)
printf(" c%d",col[i]);
sz=row.size();
rep(i,,sz-)
printf(" r%d",row[i]); printf("\n");
} int main()
{
while(~scanf("%d%d%d",&n,&m,&cnt))
{
if(!n&&!m&&!cnt)
return ;
read();
AP();
mincover();
print();
}
return ;
}
UVA 11419 SAM I AM(最大二分匹配&最小点覆盖:König定理)的更多相关文章
- nyoj 237 游戏高手的烦恼 二分匹配--最小点覆盖
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=237 二分匹配--最小点覆盖模板题 Tips:用邻接矩阵超时,用数组模拟邻接表WA,暂时只 ...
- HDU - 1150 Machine Schedule(二分匹配---最小点覆盖)
题意:有两台机器A和B,A有n种工作模式(0~n-1),B有m种工作模式(0~m-1),两台机器的初始状态都是在工作模式0处.现在有k(0~k-1)个工作,(i,x,y)表示编号为i的工作可以通过机器 ...
- Uva - 11419 - SAM I AM
题意:一个矩形——R*C的网格,在某些位置上有石头,在网格外开一炮可以打掉该行或者该列的石头,求打掉这些石头最少需要多少门大炮,位置分别设在哪行哪列(0<R<1001, 0 < C ...
- UVA - 12083 Guardian of Decency (二分匹配)
题意:有N个人,已知身高.性别.音乐.运动.要求选出尽可能多的人,使这些人两两之间至少满足下列四个条件之一. 1.身高差>40 2.性别相同 3.音乐不同 4.运动相同 分析: 1.很显然 ...
- UVA 11419 SAM I AM (最小点覆盖,匈牙利算法)
题意:给一个r*c的矩阵,某些格子中可能有一些怪物,可以在一行或一列防止一枚大炮,大炮会扫光整行/列的怪,问最少需要多少炮?输出炮的位置. 思路: 先每行和列都放一个炮,把炮当成点,把怪当成边,一边连 ...
- POJ 3020 Antenna Placement【二分匹配——最小路径覆盖】
链接: http://poj.org/problem?id=3020 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22010#probl ...
- poj2226-Muddy Fields二分匹配 最小顶点覆盖 好题
题目 给到一个矩阵,有些格子上是草,有些是水.需要用宽度为1,长度任意的若干块木板覆盖所有的水,并不能覆盖草,木板可以交叉,但只能横竖放置,问最少要多少块板. 分析 经典的矩阵二分图构图和最小点覆盖. ...
- UVa 11419 SAM I AM (最小覆盖数)
题意:给定一个 n * m 的矩阵,有一些格子有目标,每次可以消灭一行或者一列,问你最少要几次才能完成. 析:把 行看成 X,把列看成是 Y,每个目标都连一条线,那么就是一个二分图的最小覆盖数,这个答 ...
- UVA 1201 - Taxi Cab Scheme(二分图匹配+最小路径覆盖)
UVA 1201 - Taxi Cab Scheme 题目链接 题意:给定一些乘客.每一个乘客须要一个出租车,有一个起始时刻,起点,终点,行走路程为曼哈顿距离,每辆出租车必须在乘客一分钟之前到达.问最 ...
随机推荐
- Gdata XML解析配置和简单使用
导入libxml2,使用第三方AFNetworking网络请求,第三方XML解析GData GData需要的配置 Build Settings 里搜索,添加如下
- POJ 2127
#include <iostream> #define MAXN 501 using namespace std; int a[MAXN],b[MAXN],ans[MAXN]; int G ...
- 虚拟专用网络VPN
寒假回到家里需要下载论文,怎样才能访问学校图书馆的数据库呢?解决方法是学校图书馆在内网中架设一台VPN服务器,VPN服务器有两块网卡,一块连接内网,一块连接公网.然后就可以通过互联网找到VPN服务器, ...
- java 静态构造函数
在java中貌似是没有静态构造函数的. 不过用下面的方式同样可以实现效果. static { }//end 这是静态代码块
- ZOJ 2588 Burning Bridges (tarjan求割边)
题目链接 题意 : N个点M条边,允许有重边,让你求出割边的数目以及每条割边的编号(编号是输入顺序从1到M). 思路 :tarjan求割边,对于除重边以为中生成树的边(u,v),若满足dfn[u] & ...
- 初学Ajax(二)
$.get()和$.post() .load()方法是局部方法,因为它需要一个包含元素的jQuery对象作为前缀.而$.get()和$.post()是全局方法,无须指定某个元素.对于用途而言,.loa ...
- JS之事件(一)
事件:交互 异步监听,不是JS引擎监听的 一.绑定 1.ele.onxxxx(eg:onclick) = function (e) { //回调函数/事件处理函数 } 兼容性很好,但同一个事件仅能绑定 ...
- oracle连接数据
1.源代码 string connString = "User ID=scott;Password=yanhong;Data Source=(DESCRIPTION = (ADDRESS_L ...
- Linux 删除文件夹和文件的命令
linux删除目录很简单,很多人还是习惯用rmdir,不过一旦目录非空,就陷入深深的苦恼之中,现在使用rm -rf命令即可.直接rm就可以了,不过要加两个参数-rf 即:rm -rf 目录名字-r 就 ...
- lintcode: 左填充
题目 实现一个leftpad库,如果不知道什么是leftpad可以看样例 样例 leftpad("foo", 5) >> " foo" leftpa ...