原题链接

矩形分割

算法分析:

解决该题要用到“并查集”的思想。

这里有一篇不错的博客介绍并查集: 并查集(Union-Find)算法介绍

记 int total=N*M,这里会有 total 个方块,因为一道对角线(''或者'/')会把一块方块分割为左右两部分,所以,我们把任意一块方块看做左右两个部分。对于左部分,从左到右从上到下依次编号为 0~total-1;对于右部分,从做到右从上到下依次编号为 total~2*total-1;用一个 int parent[20000] (因为1<=N,M<=100; 所有最多有10000个方块,也就是最多有20000个半部分) 的数组来记录一个部分所属于的集合编号。初始化 parent[i]=i;

C++算法实现

#include<iostream>
using namespace std; int find(int parent[], int i) {
int p = parent[i];
if (p != i) {
parent[i] = find(parent, p);//如果当前节点的编组号不是自身,那么递归查询到当前编组的根节点,并修改当前节点的编组号为该编组的根节点
}
return parent[i];//返回当前节点的编组号
} void unit(int parent[], int i, int j)//合并两个编组
{
int pi = find(parent, i);
int pj = find(parent, j);
if (pi != pj)
{
if (pi < pj) {//将编组号小的根节点作为根,另一个编组挂接到该编组上
parent[pj] = pi;
}
else {
parent[pi] = pj;
}
}
} int main(int argc, char* argv[])
{ int N, M, index, total;
char wall[101][101];//墙面数据
int parent[20000];//parent[0~total-1] 为左半部分的并查集信息,parent[total~2*total-1]为右半部分的并查集信息 cin >> N >> M; cin.getline(wall[0], 101);// N 和 M 独占一行,后面的换行符没有从输入缓冲中去除掉,会影响 cin.getline()函数的结果,因此调用一次 cin.getline(wall[0],101)来去除掉该换行符
for (int i = 0; i < N; i++) {
cin.getline(wall[i], 101);
} total = N*M;//正方形数量
for (int i = 0; i < total; i++) {//初始化并查集
parent[i] = i;
parent[total + i] = total + i;
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
index = i*M + j;//正方形(i,j)左半部分在 parent 中所对应的下标
switch (wall[i][j]) {
case ' ':
if (i > 0) {//如果该正方形上方还有正方形,则将该正方形和上方正方形所属于的组进行合并
switch (wall[i - 1][j]) {
case ' ':
case '\\':
unit(parent, index, index - M);//index-M 为当前正方形上方的正方形左半部分在 parent[] 中的下标
break;
case '/':
unit(parent, index, total + index - M);//total+index-M 为当前正方形上方的正方形右半部分在 parent[] 中的下标
break;
default:
return -1;
break;
}
}
if (j > 0) {
//当前正方形左面还有正方形,则合并当前正方形左半部分和左面正方形的右半部分
unit(parent, index, total + index - 1);
}
unit(parent, total + index, index);//因为当前正方形没有被分割,所以当前正方形的左右两半部分必定属于同一个组,合并之
//另外由于当前正方形内容为空格,所以当前正方形右边的正方形和下边的正方形必然会跟当前正方形相连接,在后续的处理步骤中自然会合并它们,所以无需考虑当前正方形右面正方形和下面正方形的内容
break;
case '\\': //当前正方形的左半部分有可能跟左面正方形的右半部分、下面正方形的左半部分或右半部分相接;对应if(j>0)和if(i<N-1)的情况
if (j > 0) {
unit(parent, index, total + index - 1);
}
if (i<N - 1) {
switch (wall[i + 1][j]) {
case ' ':
case '/':
unit(parent, index, index + M);
break;
case '\\':
unit(parent, index, total + index + M);
break;
default:
return -1;
break;
}
}
//当前正方形的右半部分可能跟上面正方形的左半部分或右半部分、右面正方形的左半部分相连接;对应if(i>0)和if(j<M-1)的情况
if (i>0) {
switch (wall[i - 1][j]) {
case ' ':
case '\\':
unit(parent, total + index, index - M);
break;
case '/':
unit(parent, total + index, total + index - M);
break;
default:
return -1;
break;
}
}
if (j < M - 1) {
unit(parent, total + index, index + 1);
}
break;
case '/':
//当前正方形的左半部分可能跟上面正方形的左半部分或右半部分、左面正方形的右半部分相连接;对应 if(i>0) 和 if(j>0) 的情形
if (i > 0) {
switch (wall[i - 1][j]) {
case ' ':
case '\\':
unit(parent, index, index - M);
break;
case '/':
unit(parent, index, total + index - M);
break;
default:
return -1;
break;
}
}
if (j > 0) {
unit(parent, index, total + index - 1);
} //当前正方形的右半部分可能跟右面正方形的左半部分、下面正方形的左半部分或右半部分相连接;对应 if(j<M-1) 和 if(i<N-1) 的情况
if (j < M - 1) {
unit(parent, total + index, index + 1);
}
if (i < N - 1) {
switch (wall[i + 1][j]) {
case ' ':
case '/':
unit(parent, total + index, index + M);
break;
case '\\':
unit(parent, total + index, total + index + M);
break;
default:
return -1;
break;
}
}
break;
default:
return -1;
break;
}
}
} int ceil = total << 1;
int count = 0;
for (int i = 0; i < ceil; i++) {
if (parent[i] == i) {//如果 parent[i]==i ,那么 i 为其所在的编组的根节点
count++;
}
}
cout << count;
return 0;
}

hihocoder [Offer收割]编程练习赛12 [1495] ---- 矩形分割的更多相关文章

  1. hihocoder offer收割编程练习赛12 C 矩形分割

    思路: 模拟,深搜. 实现: #include <iostream> #include <cstdio> #include <string> using names ...

  2. hihocoder [Offer收割]编程练习赛12 [1494] ---- 一面砖墙

    原题链接 一面砖墙 算法分析 设墙的宽度为 range,则需要统计横坐标为 1,2,3,4,...,range-1 处的墙缝数,取最大的墙缝数(记为maxCrevices),从该处划一道竖线,竖线穿过 ...

  3. hihocoder offer收割编程练习赛12 D 寻找最大值

    思路: 可能数据太水了,随便乱搞就过了. 实现: #include <iostream> #include <cstdio> #include <algorithm> ...

  4. hihocoder offer收割编程练习赛12 B 一面砖墙

    思路: 就是求哪个长度出现的次数最多. 实现: #include <iostream> #include <cstdio> #include <algorithm> ...

  5. hihocoder offer收割编程练习赛12 A 歌德巴赫猜想

    思路: 枚举. 实现: #include <iostream> #include <cstdio> #include <algorithm> using names ...

  6. hihocoder [Offer收割]编程练习赛4

    描述 最近天气炎热,小Ho天天宅在家里叫外卖.他常吃的一家餐馆一共有N道菜品,价格分别是A1, A2, ... AN元.并且如果消费总计满X元,还能享受优惠.小Ho是一个不薅羊毛不舒服斯基的人,他希望 ...

  7. hihocoder [Offer收割]编程练习赛61

    [Offer收割]编程练习赛61 A:最小排列 给定一个长度为m的序列b[1..m],再给定一个n,求一个字典序最小的1~n的排列A,使得b是A的子序列. 贪心即可,b是A的子序列,把不在b中的元素, ...

  8. 【[Offer收割]编程练习赛12 C】矩形分割

    [题目链接]:http://hihocoder.com/problemset/problem/1495 [题意] [题解] 把每个方块都再分成3*3的小块; 这样; 对于一个方块来说 如果是'\' 则 ...

  9. ACM学习历程—Hihocoder [Offer收割]编程练习赛1

    比赛链接:http://hihocoder.com/contest/hihointerview3/problem/1 大概有一个月没怎么打算法了.这一场的前一场BC,也打的不是很好.本来Div1的A和 ...

随机推荐

  1. 3DMax——室内设计:墙体+吊顶

    1.导入CAD平面图 2.将导入的平面图全部选中→颜色设置为其他颜色→设置为组(设置为组,是为了后期选材质方便) 3.选中图形,选择移动工具,输入坐标为0,右键选择冻结当前选择 4.右键“角度捕捉切换 ...

  2. oracle 异常关闭操作 导致数据库无法正常关闭 也无法启动

    场景描述: 在关闭数据库的时候,命令没有打全,导致数据库没有正常关闭 解决办法: 重新建立个连接,然后切换到oracle用户 执行强制关闭数据库: OK 问题解决,不过生产环境 还是不推荐 shutd ...

  3. maven更换源

    1)在 /etc/maven/settings.xml 找到  <mirrors>  </ mirrors>标签,在标签内部 添加内容如下: <mirror>    ...

  4. N元马尔科夫链的实现

    马尔可夫模型(Markov Model)是一种统计模型,广泛应用在语音识别,词性自动标注,音字转换,概率文法等各个自然语言处理等应用领域.经过长期发展,尤其是在语音识别中的成功应用,使它成为一种通用的 ...

  5. 【Canal源码分析】client工作过程

    client的工作过程,需要我们自己去编写对应的逻辑,我们目前只能从example写的例子来看.目前examle中提供了两个例子,一个是单机的,一个是集群的cluster,我们后续如果需要进行开发的话 ...

  6. Intellij添加Jetty远程Debug

    步骤一: 步骤二: 步骤三:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=15005 步骤四: 找到服务器上jetty的b ...

  7. 记住,永远不要在MySQL中使用“utf8”编码[转载]

    记住,永远不要在MySQL中使用“utf8”编码 原创: 无明.Adam 聊聊架构 6月15日 最近工作中我遇到了一个 bug,我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一 ...

  8. Chapter 3 Phenomenon——21

    "Nobody will believe that, you know." “你知道吗没有人会相信会是这样的” His voice held an edge of derision ...

  9. Redis学习之实现优先级消息队列

    很久没有写博客了,最近简单的学习了一下Redis,其中学习了一下用Redis实现优先级消息队列.关于更多更为详细的可以在www.redis.cn找到相关资料. 对于熟悉Redis的童鞋提到队列很自然的 ...

  10. JavaScript事件-this传递

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...