题意:在方格图上打小怪,每次可以清除一整行或一整列的小怪,问最少的步数是多少,又应该在哪些位置操作(对输出顺序没有要求)。
分析:最小覆盖问题
这是一种在方格图上建立的模型:令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 题目链接 题意:给定一些乘客.每一个乘客须要一个出租车,有一个起始时刻,起点,终点,行走路程为曼哈顿距离,每辆出租车必须在乘客一分钟之前到达.问最 ...
随机推荐
-
Matlab 用fread、fwrite实现大文件读写
最近在分析一个35G的大数据文件,猛一看,是不是很吓人啊,不过还好,师兄写文件的格式非常规范,读取数据来也就很方便了,主要是使用了读写文件的两个函数fread和fwrite,下面用matlab简单尝试 ...
-
mvn命令
打包:mvn package 编译:mvn compile 编译测试程序:mvn test-compile 清空:mvn clean 运行测试:mvn test 生成站点目录: mvn site 生成 ...
-
This manual page is part of Xcode Tools version 5.0
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.ht ...
-
CSS3 设置 Table 隔行变色
table tr:nth-child(odd){background:#F4F4F4;} table td:nth-child(even){color:#C00;}
-
最短路算法之Dijkstra算法通俗解释
Dijkstra算法 说明:求解从起点到任意点的最短距离,注意该算法应用于没有负边的图. 来,看图. 用邻接矩阵表示 int[][] m = { {0, 0, 0, 0, 0, 0}, {0, 0, ...
-
P2649 - 【NOIP2017】列队
Description Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 n×m 名学生,方阵的行数为 ...
-
纯CSS修改checkbox复选框样式
借鉴网友博客, 改用后整理收录 效果图: 移入: <!DOCTYPE html> <html> <head> <meta charset="UTF- ...
-
SQL语句删除和添加外键、主键的方法
--删除外键 语法:alter table 表名 drop constraint 外键约束名 如: alter table Stu_PkFk_Sc drop constraint FK_s alter ...
-
Tensorflow r1.8安装C++接口(兼容OpenCV3)
与之前一样,直接走medium的传送门:https://medium.com/@fanzongshaoxing/use-tensorflow-c-api-with-opencv3-bacb83ca56 ...
-
Javascript-数据类型转换 、 运算符和表达式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...