这道题,看似很烦,无从下手,但其实只要用位运算联通快就能水过了呀。

首先,输入大意是把一个数拆成二进数的相加,分别表示 \((i,j)\) 东南西北是否有墙。\(1\) 表示西,\(2\) 表示北,\(4\) 表示东,\(8\) 表示南。

第一种方法,你可以写 \(15\) 个 \(\operatorname{if}\),分别枚举 \(15\) 种情况,然后求出它的二进制拆分。

第二种比较简单的方法,我们可以尝试用位运算来解决。

先来了解一下位运算中的 \(\&\)。它做的是一种运算,对于两个 \(2\) 进制,当它们的某一位都是 \(1\),则返回 \(1\),否则返回 \(0\)。

举个栗子:\(3\&11=0011\&1011=0011\)

好了,诸如 \(1,2,4,8……\) 这样的数,它们在二进制中都只能拆成\(0001,0010,0100,1000……\)。假如我们要知道某个数中能否拆成一个\(2^n\),那我们只需要拿它的二进数与 \(2^n\) 的二进制进行比较。如果它们有共同的\(1\),则说明 \(2^n\) 是其拆出来的一个数。

那么接下来,即可考虑设一个数组 \(a[i][j][k]\),表示对于某个房间 \((i,j)\),其 \(k\) 方向是否有墙。

注意 \(0\) 表示西方,\(1\) 表示北方,\(2\) 表示东方,\(3\) 表示南方。

const int dir[5][5]={
{0,-1},{-1,0},{0,1},{1,0}//方向
};
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x;
cin>>x;
if(x&1)a[i][j][0]=1;
if(x&2)a[i][j][1]=1;
if(x&4)a[i][j][2]=1;
if(x&8)a[i][j][3]=1;
//位运算,1表示有墙
}
}

下面可以切入主程序了。

  • 对于第一二问,题目是要求联通快的个数以及最大的联通快的面积。

这个很简单,我们用\(dfs\)遍历所有点。每个点扩展出他的所有联通快,并且记录最大的面积即可。

  • 对于第三四问,题目是要我们找拆掉哪面墙才能使得新房间的大小尽可能大。

其实说白了还是枚举,我们要暴搜所有的墙。假如拆掉了 \((i,j)\) 北面的墙,则 \((i-1,j)\) 南面的墙也会被拆掉。假如拆掉了 \((i,j)\) 东面的墙,则 \((i+1,j)\) 西面的墙也会被拆掉。

故在拆墙的过程中,可能会影响到许多的房间,这是我们要特殊考虑的。

\(\operatorname{Code}:\)

#include<bits/stdc++.h>
using namespace std;
int n,m,a[60][60][10],h[60][60];
int sum,area,max_area;
int ansx,ansy,ansfx;
const int dir[5][5]={
{0,-1},{-1,0},{0,1},{1,0}//方向
};
void dfs(int x,int y){
h[x][y]=1,area++;
for(int i=0;i<4;i++){
if(a[x][y][i])continue;//有墙!
int tx=x+dir[i][0];
int ty=y+dir[i][1];//下一个点
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&h[tx][ty]==0){
//未超边界且可以走
dfs(tx,ty);
}
}
}
void find_(int x,int y,int fx){//查找联通快
memset(h,0,sizeof(h));//清零!
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(h[i][j])continue;
area=0;
dfs(i,j),sum++;//查找联通快
if(area>max_area){
max_area=area;//更新最大面积
ansx=x,ansy=y,ansfx=fx;//记录坐标,方向
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>m>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x;
cin>>x;
if(x&1)a[i][j][0]=1;
if(x&2)a[i][j][1]=1;
if(x&4)a[i][j][2]=1;
if(x&8)a[i][j][3]=1;
//位运算,1表示有墙
}
}
find_(0,0,0);
cout<<sum<<endl;
cout<<max_area<<endl;
max_area=0;
for(int j=1;j<=m;j++){
for(int i=n;i>=1;i--){
for(int k=1;k<3;k++){
if(a[i][j][k]==0)continue;
a[i][j][k]=0;
if(k==1)a[i-1][j][3]=0;
if(k==2)a[i][j+1][0]=0;
find_(i,j,k);
a[i][j][k]=1;
if(k==1)a[i-1][j][3]=1;
if(k==2)a[i][j+1][0]=1;
}
}
}
cout<<max_area<<endl;
char ansch;
if(ansfx==1)ansch='N';
else ansch='E';//判断方向
cout<<ansx<<" "<<ansy<<" "<<ansch<<endl;
return 0;
}

\(\operatorname{Update}\) \(\operatorname{On}\) \(\operatorname{2019.05.17}\)

题解 洛谷P1457 【城堡 The Castle】的更多相关文章

  1. 洛谷P1457 城堡 The Castle

    P1457 城堡 The Castle 137通过 279提交 题目提供者该用户不存在 标签USACO 难度提高+/省选- 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 我们憨厚的USACO ...

  2. 洛谷 P1457 城堡 The Castle 解题报告

    P1457 城堡 The Castle 题目描述 我们憨厚的USACO主人公农夫约翰(Farmer John)以无法想象的运气,在他生日那天收到了一份特别的礼物:一张"幸运爱尔兰" ...

  3. 洛谷 P1457 城堡 The Castle

    P1457 城堡 The Castle 题目描述 我们憨厚的USACO主人公农夫约翰(Farmer John)以无法想象的运气,在他生日那天收到了一份特别的礼物:一张“幸运爱尔兰”(一种彩票).结果这 ...

  4. 洛谷—— P1457 城堡 The Castle

    https://www.luogu.org/problem/show?pid=1457 题目描述 我们憨厚的USACO主人公农夫约翰(Farmer John)以无法想象的运气,在他生日那天收到了一份特 ...

  5. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  6. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  7. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  8. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

  9. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

随机推荐

  1. csu 1987: 绚丽的手链

    1987: 绚丽的手链 Submit Page   Summary   Time Limit: 6 Sec     Memory Limit: 512 Mb     Submitted: 13     ...

  2. spring 循环引用问题,在一次问题调试过程中发现有个小伙伴竟然把循环引用设置成false了。估计是百度的时候没小心额外的代码吧。。。

    循环引用属性操作: 1)AbstractAutowireCapableBeanFactory类中的allowCircularReferences被设置为了false. 2)代码: Annotation ...

  3. Vue(六)插槽(2.6.0+)

    插槽在vue2.6.0开始有了新的更新 具名插槽(数据来自父组件) 子组件(定义插槽)这里版本前后没什么变化 <template> <div> <header> & ...

  4. 09 Servlet相关知识点---学习笔记

    1.概念:运行在服务器端的小程序 Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则.将来我们自定义一个类,实现Servlet接口,复写方法. 2.快速入门:(1)创 ...

  5. Shell编程学习记录

    一.shell中单引号和双引号的区别: 1).单引号属于强引用,它会忽略所有被引起来的字符的特殊处理,被引用起来的字符会被原 封不动的使用,唯一需要注意的点是不允许引用自身: 2).双引号属于弱引用, ...

  6. 深入Java中的位操作

    「WTF系列」深入Java中的位操作 关于WTF系列 引 学完本章节你将学会位的基础概念与语法,并且还会一些骚操作!! 与.或.非.位移 原码.反码.补码 字节.位.超区间...... 开始本章节之前 ...

  7. 中国大学MOOC-翁恺-C语言程序设计习题集(一)

    练习 02-0. 整数四则运算(10) 本题要求编写程序,计算2个正整数的和.差.积.商并输出.题目保证输入和输出全部在整型范围内. 输入格式: 输入在一行中给出2个正整数A和B. 输出格式: 在4行 ...

  8. Linux 环境安装 Node、nginx、docker、vsftpd、gitlab

    Linux 环境安装 centos7 # 更新yum yum update -y 0. 防火墙 firewalld 新入的JD云服务器,发现防火墙默认是关闭的. # 查看防火墙状态 systemctl ...

  9. IP核——RAM

    一.Quartus 1.打开Quartus ii,点击Tools---MegaWizard Plug-In Manager 2.弹出创建页面,选择Creat a new custom megafunc ...

  10. 微信小程序自定义组件,提示组件

    微信小程序自定义组件,这里列举了一个常用的提示自定义组件,调用自定义组件中的方法和字段.仅供参考和学习. 编写组件: 在根目录下添加“components”目录,然后像添加Page页面一样添加自定义组 ...