uva 11419 最大匹配(最小点覆盖)

链接:https://vjudge.net/problem/27475

题意:给定一个二维矩阵,在一些格子里放置了东西,然后你有一门炮,每次能横向或纵向开一炮,将这一行所有的东西摧毁。问你最少花多少炮弹摧毁所有的东西?并输出一组解。

题解:

  很久之前做的题目了,今天在看到的时候还是很有新的体会的。这是一个求最小覆盖的问题,最小点覆盖,将行列的每个点看作是x,y集合,将放置的东西的地方看作是边(大白书)。然后求一次最大匹配,会得出来至少有多个点是不在同一行和同一列的,这样剩余的东西就会与原来的已匹配的点在同一行或者同一列,求完最大匹配后,可以得出开枪的次数,然后进行求方案数。从未匹配的点开始拓展,第一次没有参与匹配的点 在哪一行最多 或者在哪一列最多 那么肯定开枪位置就在这一行 或者这一列,这里的左右集合表现的很明显,因为记录 路径的缘故。

参考代码:

#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <iostream>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1011;
int mp[maxn][maxn];
int machl[maxn],machr[maxn],visx[maxn],visy[maxn];
int n,m,k;
bool dfs(int u)
{
    visx[u]=1;
    for(int i=1;i<=m;i++)
        if(!visy[i]&&mp[u][i])
        {
            visy[i]=true;
            if(machr[i]==-1||dfs(machr[i]))
            {
                machl[u]=i;//列匹配
                machr[i]=u;//行匹配
                return true;
            }
        }
    return false;
}
int Maxmach()
{
    int ans=0;
    memset(machl,-1,sizeof(machl));
    memset(machr,-1,sizeof(machr));
    for(int i=1;i<=n;i++)
    {
        memset(visy,0,sizeof(visy));
        if(dfs(i))
            ans++;
    }
    return ans;
}
int  main()
{
    //freopen("C:\\Users\\Administrator\\Desktop\\a.txt","r",stdin);
    int a,b;
    while(scanf("%d%d%d",&n,&m,&k),n+m+k)
    {
        memset(mp,0,sizeof(mp));
        for(int i=0;i<k;i++)
            scanf("%d%d",&a,&b),mp[a][b]=1;
        int Ans=Maxmach();
        printf("%d",Ans);

        //求方案数

        memset(visx,0,sizeof(visx));
        memset(visy,0,sizeof visy);
        for(int i=1;i<=n;i++)  //从x中未匹配的点出发
            if(machl[i]==-1) dfs(i);
        for(int i=1;i<=n;i++)
            if(!visx[i]) printf(" r%d",i);
        for(int i=1;i<=m;i++)
            if(visy[i]) printf(" c%d",i);
        printf("\n");
    }
    return 0;
}

  

时间: 2024-10-07 17:56:42

uva 11419 最大匹配(最小点覆盖)的相关文章

二分图 最大匹配 最小点覆盖 最大独立子集

①一个二分图中的最大匹配数等于这个图中的最小点覆盖数 ②最大独立子集=点数-最小点覆盖数

POJ1463 Strategic game (最小点覆盖 or 树dp)

题目链接:http://poj.org/problem?id=1463 给你一棵树形图,问最少多少个点覆盖所有的边. 可以用树形dp做,任选一点,自底向上回溯更新. dp[i][0] 表示不选i点 覆盖子树所有边的最少点个数,那选i点的话,那么i的邻接节点都是必选的,所以dp[i][0] += dp[i.son][1] dp[i][1] 表示选i点 覆盖子树所有边的最少点个数,那么i的邻接点可选可不选(而不是一定不选,看注释样例就知道了),所以dp[i][0] += min(dp[i.son][

四川第七届 D Vertex Cover(二分图最小点覆盖,二分匹配模板)

Vertex Cover frog has a graph with nn vertices v(1),v(2),-,v(n)v(1),v(2),-,v(n) and mm edges (v(a1),v(b1)),(v(a2),v(b2)),-,(v(am),v(bm))(v(a1),v(b1)),(v(a2),v(b2)),-,(v(am),v(bm)). She would like to color some vertices so that each edge has at least

UVA 11419 - SAM I AM(二分图匹配+最小点覆盖)

UVA 11419 - SAM I AM 题目链接 题意:给定一个棋盘,上面有一些目标,现在要放炮,一个炮能打一行或一列,问最少放几个炮及放炮位置 思路:首先是二分图匹配,每个目标行列建边,做二分图匹配就是最少的放炮位置,至于输出方案,利用最小点覆盖的Konig原理去做,详细证明 代码: #include <cstdio> #include <cstring> #include <vector> using namespace std; const int N = 10

UVa 11419 我是SAM(最小点覆盖+路径输出)

https://vjudge.net/problem/UVA-11419 题意:一个网格里面有一些目标,可以从某一行,某一列发射一发子弹,可以打掉它:求最少的子弹,和在哪里打? 思路: 每个点的x坐标与y坐标相连,现在就是要找一个最小点覆盖,同时还要输出哪些点被覆盖了. 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <algorithm> 5 using nam

二分图最大匹配,最小路径覆盖,最小点覆盖,最大独立集,最小边覆盖与建图方法

转载请注明出处(别管写的好坏,码字也不容易):http://blog.csdn.net/hitwhacmer1 前言:         有自己写的,有摘的别人的,前面是摘的,也是无心整理,出错是难免的,反正我都不会证明,智人见智,别被我误导了. §1图论点.边集和二分图的相关概念和性质 点覆盖.最小点覆盖 点覆盖集即一个点集,使得所有边至少有一个端点在集合里.或者说是"点" 覆盖了所有"边"..极小点覆盖(minimal vertex covering):本身为点覆

训练指南 UVA - 11419(二分图最小覆盖数)

layout: post title: 训练指南 UVA - 11419(二分图最小覆盖数) author: "luowentaoaa" catalog: true mathjax: true tags: - 二分图 - 最小点覆盖 - 图论 - 训练指南 SAM I AM UVA - 11419 题目大意:给出一个R×C的网格,网格上棉纺了一些目标.可以在网格外发射子弹,子弹会沿着垂直或水平方向飞行,并且打掉飞行路径上的所有目标.你的任务是计算出最少需要多少子弹,各从哪个位置发射,才

POJ1325_Machine Schedule(二分图/最小点覆盖=最大匹配)

解题报告 http://blog.csdn.net/juncoder/article/details/38147135 题目传送门 题意: A机器有n个模式,B机器有m个模式,每个作业可以在任何机器的特定模式下工作,转换模式需要耗时,求最小耗时 思路: 把AB两机器的模式当成二分图顶点,模式之间的连线就是某个作业可以在该两个模式下工作,就转换成求最小点覆盖,用最少的点覆盖最多的边. 最小点覆盖=最大匹配 #include <queue> #include <cmath> #incl

关于最大匹配,最小点覆盖,最少路径覆盖和最大独立集的总结

(1)二分图的最大匹配 匈牙利算法 (2)二分图的最小点覆盖 二分图的最小点覆盖=二分图的最大匹配 求最小点覆盖:从右边所有没有匹配过的点出发,按照增广路的“交替出现”的要求DFS.最终右边没有访问过的点和左边访问过的点组成最小点覆盖. 证明见这里 (3)二分图的最少边覆盖 二分图的最少边覆盖=点数-二分图的最大匹配 证明: 先贪心选一组最大匹配的边放进集合,对于剩下的没有匹配的点,随便选一条与之关联的边放进集合,那么得到的集合就是最小边覆盖. 所以有:最小边覆盖=最大匹配+点数-2*最大匹配=