题目大意:给定一地图,*可以和相邻的*匹配成一对儿,问最少需要对儿匹配才能使所有*都被匹配到。

很直白的最小点覆盖,即ans = 点集数-最大匹配数。

不过一开始要对图进行遍历得到点集,找到一个*就把点集数+1,并和周围的匹配即可。为了防止重复,

我只匹配了左边和上边的点。由于用邻接表保存了双向路,所以最后匹配结果会是最大匹配的二倍。

数据范围是40*10,匈牙利即可,因此不用Karp进行优化。

附AC代码:

#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define oo 0x3f3f3f3f
char maps[][];
int nums[][];
struct ad
{
int next, to;
} edge[];
int head[], edge_num, used[], vis[];
void Add(int x, int y)
{
edge[edge_num].next = head[x];
edge[edge_num].to = y;
head[x] = edge_num++;
}
bool Hungary(int u)
{
for(int i=head[u]; i!=-; i=edge[i].next)
{
int To = edge[i].to;
if(!vis[To])
{
vis[To] = ;
if(!used[To] || Hungary(used[To]))
{
used[To] = u;
return true;
}
} }
return false;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int m, n;
scanf("%d %d", &m, &n);
for(int i=; i<m; i++)
scanf("%s", maps[i]);
int cnt = ;
memset(head, -, sizeof(head));
edge_num = ;
for(int i=; i<m; i++)
for(int j=; j<n; j++)
{
if(maps[i][j]=='*')
{
cnt++;
nums[i][j] = cnt;
if(i>= && maps[i-][j]=='*')
{
Add(nums[i-][j], nums[i][j]);
Add(nums[i][j], nums[i-][j]);
}
if(j>= && maps[i][j-]=='*')
{
Add(nums[i][j], nums[i][j-]);
Add(nums[i][j-], nums[i][j]);
}
}
}
memset(used, , sizeof(used));
int ans = ;
for(int i=; i<=cnt; i++)
{
memset(vis, , sizeof(vis));
if(Hungary(i))ans++;
}
printf("%d\n", cnt-ans/);
}
return ;
}

Karp算法优化代码:

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
using namespace std;
#define oo 0x3f3f3f3f
const int Maxn = ;
char maps[][];
int nums[][], head[Maxn];
struct ad
{
int to, next;
}edge[Maxn*Maxn];
int depth, depx[Maxn], depy[Maxn], vis[Maxn], usedx[Maxn], usedy[Maxn], edge_num;
void Add(int x, int y)
{
edge[edge_num].to = y;
edge[edge_num].next = head[x];
head[x] = edge_num++;
}
bool bfs(int cnt)
{
memset(depx, -, sizeof(depx));
memset(depy, -, sizeof(depy));
depth = oo;
queue<int>Q;
for(int i=; i<=cnt; i++)
{
if(!usedx[i])
{
depx[i] = ;
Q.push(i);
}
} while(Q.size())
{
int now = Q.front();
Q.pop();
if(depx[now]>depth)return true; for(int i=head[now]; i!=-; i=edge[i].next)
{
int To = edge[i].to;
if(depy[To] == -)
{
depy[To] = depx[now] + ;
if(!usedy[To])
depth = depy[To];
else
{
depx[usedy[To]] = depy[To] + ;
Q.push(usedy[To]);
}
}
}
} if(depth==oo)return false;
return true;
}
bool Hungary(int u)
{
for(int i=head[u]; i!=-; i=edge[i].next)
{
int To = edge[i].to;
if(!vis[To])
{
vis[To] = ;
if(usedy[To] && depy[To]==depth)continue; if(!usedy[To] || Hungary(usedy[To]))
{
usedx[u] = To;
usedy[To] = u;
return true;
}
}
}
return false;
}
int Karp(int cnt)
{
memset(usedx, , sizeof(usedx));
memset(usedy, , sizeof(usedy)); int ans = ; while(bfs(cnt))
{
memset(vis, , sizeof(vis));
for(int i=; i<=cnt; i++)
if(!usedx[i] && Hungary(i))ans++;
}
return ans;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n, m;
edge_num = ;
scanf("%d %d", &n, &m);
for(int i=; i<n; i++)
scanf("%s", maps[i]);
memset(head, -, sizeof(head));
int cnt = ;
for(int i=; i<n; i++)
for(int j=; j<m; j++)
{
if(maps[i][j]=='*')
{
cnt++;
nums[i][j] = cnt;
if(i->= && maps[i-][j]=='*')
{
Add(nums[i-][j], nums[i][j]);
Add(nums[i][j], nums[i-][j]);
}
if(j->= && maps[i][j-]=='*')
{
Add(nums[i][j], nums[i][j-]);
Add(nums[i][j-], nums[i][j]);
}
}
}
int ans = Karp(cnt);
printf("%d\n", cnt-ans/);
}
return ;
}

POJ3020 匹配的更多相关文章

  1. POJ-3020 Antenna Placement---二分图匹配&最小路径覆盖&建图

    题目链接: https://vjudge.net/problem/POJ-3020 题目大意: 一个n*m的方阵 一个雷达可覆盖两个*,一个*可与四周的一个*被覆盖,一个*可被多个雷达覆盖问至少需要多 ...

  2. POJ3020:Antenna Placement(二分图匹配)

    Antnna Placement Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11093   Accepted: 5459 ...

  3. POJ3020【二分匹配】

    思路: ---说给自己 一开始想的是从1-h*w标记整幅图,建图是星号和 {他,与他相连的星号} 建边,肯定要去匹配"*"啊,所以空格一定不会去造,然后就理解成了最小点覆盖,然而对 ...

  4. POJ3020 二分图匹配——最小路径覆盖

    Description The Global Aerial Research Centre has been allotted the task of building the fifth gener ...

  5. poj3020二分图匹配

    The Global Aerial Research Centre has been allotted the task of building the fifth generation of mob ...

  6. poj3020 二分图匹配 最大独立集

    这是一道水题, 这里是最大流解法,之后再补 坑在又忘了反向建边了 题意:给你二维bool数组,让你求出能用多米诺骨牌覆盖所有 1 且骨牌最少的放法(因为多米诺骨牌1*2的结构方便描述,原题没有),原本 ...

  7. POJ3020——Antenna Placement(二分图的最大匹配)

    Antenna Placement DescriptionThe Global Aerial Research Centre has been allotted the task of buildin ...

  8. poj3020 Antenna Placement 匈牙利算法求最小覆盖=最大匹配数(自身对应自身情况下要对半) 小圈圈圈点

    /** 题目:poj3020 Antenna Placement 链接:http://poj.org/problem?id=3020 题意: 给一个由'*'或者'o'组成的n*m大小的图,你可以用一个 ...

  9. javascript匹配各种括号书写是否正确

    今天在codewars上做了一道题,如下 看上去就是验证三种括号各种嵌套是否正确书写,本来一头雾水,一种括号很容易判断, 但是三种怎么判断! 本人只是个前端菜鸟,,不会什么高深的正则之类的. 于是,在 ...

随机推荐

  1. :before和 :after

    :before和:after的作用就是在指定的元素内容(而不是元素本身)之前或者之后插入一个包含content属性指定内容的行内元素,最基本的用法如下: #example:before { conte ...

  2. JSTL函数标签库 fn标签

    JSTL函数标签库 fn标签 在使用jstl的函数标签库之前需要在页面中引入: <%@ taglib prefix="fn" uri="http://java.su ...

  3. Struts2从一个action转到另一个action的两种方法

    在Struts2中,Action处理完用户请求后,将会返回一个字符串对象,这个字符串对象就是一个逻辑视图名.Struts 2通过配置逻辑视图名和物理视图之间的映射关系,一旦系统收到Action返回的某 ...

  4. imx6移植ffmpeg2.3

    yasm ./configure --enable-shared --prefix=/usr/local/arm/yasm --host=arm-linux 修改Makefile CC=arm-non ...

  5. 深入探索c++对象模型

    第一章关于对象 c++在布局和存取时间的额外负担主要有virtual引起 virtual function:运行期动态绑定 virtual base class :base class多次出现在派生类 ...

  6. 采用TCP协议实现PIC18F97J60 ethernet bootloader

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). TCP/IP Stac ...

  7. 改变BootStrap主题颜色

    摘自:http://www.asp.net/visual-studio/overview/2013/creating-web-projects-in-visual-studio#bootstrap Y ...

  8. IT界里的生日

    MS-DOS    1981年7月27日 windows 3.0  1990年5月22日 windows 3.11  1992年3月18日 Windows 95  1995年8月24日 Windows ...

  9. 38、重新复习javascript之三

    前言 虽然吧,每天都没有什么太有技术性的工作者,但是技术不能丢,希望也要有,人如果没有希望那不就和咸鱼一样了吗?小伙加油吧 1.html与javascript结合 <!DOCTYPE html ...

  10. [转]配置sonar、jenkins进行持续审查

    本文以CentOS操作系统为例介绍Sonar的安装配置,以及如何与Jenkins进行集成,通过pmd-cpd.checkstyle.findbugs等工具对代码进行持续审查. 一.安装配置sonar ...