原题链接

矩形分割

算法分析:

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

这里有一篇不错的博客介绍并查集: 并查集(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. es 修改拼音分词器源码实现汉字/拼音/简拼混合搜索时同音字不匹配

    [版权声明]:本文章由danvid发布于http://danvid.cnblogs.com/,如需转载或部分使用请注明出处 在业务中经常会用到拼音匹配查询,大家都会用到拼音分词器,但是拼音分词器匹配的 ...

  2. sql 游标 跳出循环 和进入下一个循环

    1  使用break 结束整个循环. 2  使用continue 结束当前循环,进入下已循环. 注意:使用continue造成死循环,是因为continue后又执行与上次相同的fetch了. 解决办法 ...

  3. NPOI读取excel文件导出数据, 而此时文件正在打开中抛异常怎么办

    项目中需要用到一些数值表格, 方便起见都是用excel来的. 而如果excel正打开中, 直接使用npoi制作的工具来导出数据的话, 在这一行将会异常: workbook = new XSSFWork ...

  4. 课程二(Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization),第三周(Hyperparameter tuning, Batch Normalization and Programming Frameworks) —— 2.Programming assignments

    Tensorflow Welcome to the Tensorflow Tutorial! In this notebook you will learn all the basics of Ten ...

  5. python使用(一)

    1.hellopython.py 2.base_option.py 3.str_option.py 4.time_option.py hellopython.py # coding=utf8 __au ...

  6. JAVA框架之Spring【Spring事务详解】

    spring提供的事务管理可以分为两类:编程式的和声明式的.编程式的,比较灵活,但是代码量大,存在重复的代码比较多:声明式的比编程式的更灵活.编程式主要使用transactionTemplate.省略 ...

  7. 微信 OAuth2 网页授权获取用户信息

    文档:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html !!! 微信跟用户没有关系类接口采用了OAUTH2 [ ...

  8. 浅谈Retrofit2+Rxjava2

    近几年,Retrofit犹如燎原之火搬席卷了整个Android界.要是不懂Retrofit,简直不好意思出门...由于近几个项目都没用到Retrofit,无奈只能业余时间自己撸一下,写的不好的地方,还 ...

  9. 处理 Maven 项目名称红色感叹号的问题

    问题描述: maven 本地仓库位置移动 ,重启IDE,项目出现感叹号. 解决方案: 附加: 其它原因,造成项目感叹号,且pom.xml和Build Path下又没有相应的错误的提示的情况下. 那么选 ...

  10. 导出txt文件

    <?php Header( "Content-type: application/octet-stream "); Header( "Accept-Ranges: ...