热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[题解]CF1534F1FallingSand(EasyVersion)

题目链接#1.0题目大意一个网格图,#表示沙子,.表示空,你可以选择某些沙子使其掉落,沙子掉落过程中会扰动它下落路径周围四格(上下左右)的沙子,使他们一同掉落,问最少选择几块沙子可

题目链接


#1.0 题目大意

一个网格图,# 表示沙子,. 表示空,你可以选择某些沙子使其掉落,沙子掉落过程中会扰动它下落路径周围四格(上下左右)的沙子,使他们一同掉落,问最少选择几块沙子可以使全部沙子掉落。


#2.0 思路


#2.1 整体想法

考虑将 “扰动” 这一关系转化成边,“扰动” 这一关系是单向的,即若 \(A\) 能扰动 \(B\),不代表 \(B\) 能扰动 \(A\)。

将图中的 # 用 “扰动” 为边连接后会得到一张有向图,我们发现,在这张图中存在许多强连通分量(SCC),很显然,每一个 \(\text{SCC}\) 中的沙子扰动任意一个,该 \(\text{SCC}\) 中的所有沙子都会掉落,那么我们便可以将每个 \(\text{SCC}\) 看做一个点,即用 \(\text{Tarjan}\) 算法进行缩点。

缩点之后会得到一个有向无环图(DAG),在这张图上,无论如何都不会被扰动的点就是我们要选择的点。那么我们只需要知道这张 \(\text{DAG}\) 中有多少个入度为 \(0\) 的点即可。

下面来看每一步的细节。


#2.2 储存

题目中只给了这样一条对网格大小的限制:

\[n\cdot m\leq400000.
\]

也就是说,\(n\) 和 \(m\) 都有可能达到 \(4\cdot10^5\) 的级别,我们并不能直接开两维大小都是 \(4\cdot10^5\) 的二维数组进行储存。但是,格子的数量范围是确定的,我们可以直接开一维数组 mp[400010] 来储存格子的信息。

转换方法也很简单,将格子 \((i,j)\) 编号为 \((i-1)\cdot m+j\) 即可,其实就是自左而右、自上而下地编号。

inline int get_ind(const int &i,const int &j){
return (i - 1) * m + j;
}

#2.3 建图

找到真正可能出现的 “扰动” 并转化成边是建图的关键。我们来看一个沙子 \(A\) 下落时究竟可能会扰动哪些沙子(假设这些沙子存在)。



  • \(A\) 正上方一格的沙子;

  • \(A\) 正下方距离最近的沙子;

  • \(A\) 左边一列,比 \(A\) 正下方距离最近的沙子高度更高的最高的沙子。

  • \(A\) 右边一列,比 \(A\) 正下方距离最近的沙子高度更高的最高的沙子。

上图中,\(A\) 被选中,只有 \(B,C,D,E\) 会被扰动,因为 \(F\) 会被 \(D\) 先扰动,\(G\) 会先被 \(C\) 扰动,正对应了我们上面的四种情况。

当然,假若 \(C\) 不存在,\(G\) 也不会被 \(A\) 扰动,显然 \(B\) 会比 \(A\) 更早接触 \(G.\)


#2.4 缩点 & 统计

缩点正常用 \(\text{Tarjan}\) 缩点即可。

因为我用的链式前向星存图,记录了边的数量,在统计时直接枚举每条边,判断该边两端点是否在同一 \(\text{SCC}\) 中,如果不在,将终点所在的 \(\text{SCC}\) 的入度加一即可。

这里不用去重边,因为入度只要有,再多也是有,入度要没有,咋整也没有。

之后统计入度为 \(0\) 的 \(\text{SCC}\) 的数量即可。


#3.0 代码实现

const int N = 500010;
const int INF = 0x3fffffff;
struct Edge{
int u,v;
int nxt;
};
Edge e[N <<2];
char mp[N];
int n,m,a[N],head[N],cnt = 1,ck[N];
int T,dfn[N],low[N],inst[N],st[N],frt;
int scc[N],scnt,icnt[N],ans;
/*获取格子的编号*/
inline int get_ind(const int &i,const int &j){
return (i - 1) * m + j;
}
/*加边*/
inline void add(const int &u,const int &v){
e[cnt].u = u;
e[cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt ++;
}
inline void tarjan(int x){ // Tarjan 算法缩点
dfn[x] = low[x] = ++ T;
inst[x] = true;st[++ frt] = x;
for (int i = head[x];i;i = e[i].nxt)
if (!dfn[e[i].v]){
tarjan(e[i].v);
low[x] = min(low[x],low[e[i].v]);
}
else if (inst[e[i].v])
low[x] = min(low[x],dfn[e[i].v]);
if (dfn[x] == low[x]){
int y = 0;++ scnt;
do{
y = st[frt --];
scc[y] = scnt;
inst[y] = false;
}while (y != x);
}
}
int main(){
scanf("%d%d",&n,&m);
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= m;j ++)
cin >> mp[get_ind(i,j)];
for (int i = 1;i <= n;i ++)
scanf("%d",&a[i]);
/*建图*/
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= m;j ++){
if (mp[get_ind(i,j)] == '#'){
ck[get_ind(i,j)] = true;//标记为沙子
if (i > 1 && mp[get_ind(i - 1,j)] == '#')//如果正上方一格有沙子
add(get_ind(i,j),get_ind(i - 1,j));
/*找正下方最近的沙子*/
for (int k = i + 1;k <= n;k ++)
if (mp[get_ind(k,j)] == '#'){
add(get_ind(i,j),get_ind(k,j));
break;
}
/*左边一列,比正下方距离最近的沙子高度更高的最高的沙子*/
if (j > 1) for (int k = i;k <= n && (mp[get_ind(k,j)] != '#' || k == i);k ++)
if (mp[get_ind(k,j - 1)] == '#'){
add(get_ind(i,j),get_ind(k,j - 1));
break;
}
/*右边一列,比正下方距离最近的沙子高度更高的最高的沙子*/
if (j if (mp[get_ind(k,j + 1)] == '#'){
add(get_ind(i,j),get_ind(k,j + 1));
break;
}
}
}
/*找 SCC, 缩点*/
for (int i = 1;i <= n * m;i ++)
if (ck[i] && !dfn[i]) tarjan(i);
for (int i = 1;i if (scc[e[i].u] != scc[e[i].v])
icnt[scc[e[i].v]] ++;//统计入度
for (int i = 1;i <= scnt;i ++)
if (!icnt[i]) ans ++;//统计答案
printf("%d",ans);
return 0;
}

End

希望能给您带来收获。



推荐阅读
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
author-avatar
土豆小妈姐_645
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有