当前位置: 首页 > news >正文

CSP认证准备第三天-差分及第36次CCF认证(BFS)

基础知识参考:

csp突击前两题常用算法代码_ccf csp常用优化算法-CSDN博客

差分

什么是差分数组?

差分数组是原数组相邻元素之间的差值构成的数组。对于原数组 a,其差分数组 b 定义为:

  • b[1] = a[1] (假设 a[0] = 0)

  • b[i] = a[i] - a[i-1] (对于 i > 1)

为什么差分数组有用?

差分数组的神奇之处在于:对原数组的区间加减操作可以转化为对差分数组的两个单点操作

差分例题

一个长度为n的整数序列。
对其进行m次操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。
请你输出进行完所有操作后的序列。

###输入格式
第一行包含两个整数n和m。
第二行包含n个整数,表示整数序列。
接下来m行,每行包含三个整数l,r,c,表示一个操作。
###输出格式
共一行,包含n个整数,表示最终序列。
###数据范围
1≤n,m≤100000,
1≤l≤r≤n,
−1000≤c≤1000,
−1000≤整数序列中元素的值≤1000

如果用暴力做法每次都循环一遍区间的值然后操作的话时间肯定会超限
所以用一种巧妙地方法就是构造差分数组,
对区间[l,r]进行+c操作时只需要在差分数组里对b[l] += c,b[r+1] -= c
然后累和恢复数组时就可对区间内所有数+c

区间更新原理

当我们要对原数组 a 的区间 [l, r] 中每个元素加 c 时:

  1. 对差分数组 b[l] += c:这使得 a[l] 及之后的所有元素都增加了 c

  2. 对差分数组 b[r+1] -= c:这抵消了 a[r+1] 及之后元素的增加,使得只有 [l, r] 区间内的元素增加了 c

恢复原数组

通过计算差分数组的前缀和,我们可以恢复出更新后的原数组:

  • a'[i] = b[1] + b[2] + ... + b[i]

或者下标直接从1开始比较好:

#include<iostream>
using namespace std;
int a[100010], b[100010];
int main(){int n, m;cin>>n>>m;for(int i = 1; i <= n; i ++){cin>>a[i];b[i] = a[i] - a[i - 1];	//构造差分数组}while(m --){int l, r, c;cin>>l>>r>>c;b[l] += c;	b[r + 1] -= c;}for(int i = 1; i <= n; i ++){b[i] = b[i] + b[i - 1];cout<<b[i]<<" ";}return 0;
}

第36次CCF认证-第四题

 参考题解:

CCF-CSP第36次认证第四题——跳房子【NA!巧妙利用BFS】_csp跳房子-CSDN博客

第36次ccf-csp题解(思维) - devoteeing - 博客园

  应该属于经典题,BFS寻找最短路径,我还是不太熟悉,需要多多刷题啊。依稀记得当时有过短短的挣扎,然而确实是练少了,真的想不起来。(OK啊,后面我要系统练一下搜索算法了)

  好吧,承认我读完题目之后真的毫无头绪,这种求最优解法的题目我真的束手无措。

BFS

参考资料:

BFS(图论) - OI Wiki

第十三章 DFS与BFS(保姆级教学!!超级详细的图示!!)_dfs bfs-CSDN博客

BFS 全称是 Breadth First Search,中文名是宽度优先搜索,也叫广度优先搜索。

是图上最基础、最重要的搜索算法之一。

所谓宽度优先。就是每次都尝试访问同一层的节点。 如果同一层都访问完了,再访问下一层。

这样做的结果是,BFS 算法找到的路径是从起点开始的 最短 合法路径。换言之,这条路径所包含的边数最小。

在 BFS 结束时,每个节点都是通过从起点到该点的最短路径访问的。

算法过程可以看做是图上火苗传播的过程:最开始只有起点着火了,在每一时刻,有火的节点都向它相邻的所有节点传播火苗。

例题1-走迷宫

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=110;
typedef pair<int,int> PII;
int map[N][N],mark[N][N];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1},n,m,ans;
void bfs()
{memset(mark,-1,sizeof mark);queue<PII>q;q.push({0,0});mark[0][0]=0;while(!q.empty()){PII top=q.front();for(int i=0;i<4;i++){int nex=top.first+dx[i],ney=top.second+dy[i];if(nex>=0&&nex<n&&ney>=0&&ney<m&&mark[nex][ney]==-1&&map[nex][ney]==0){mark[nex][ney]=mark[top.first][top.second]+1;q.push({nex,ney});}}q.pop();}cout<<mark[n-1][m-1];
}
int main()
{cin>>n>>m;for(int i=0;i<n;i++){for(int j=0;j<m;j++){scanf("%d",&map[i][j]);}}bfs();
}

BFS模版

void bfs(int u) {while (!Q.empty()) Q.pop();Q.push(u);vis[u] = 1;d[u] = 0;p[u] = -1;while (!Q.empty()) {u = Q.front();Q.pop();for (int i = head[u]; i; i = e[i].nxt) {if (!vis[e[i].to]) {Q.push(e[i].to);vis[e[i].to] = 1;d[e[i].to] = d[u] + 1;p[e[i].to] = u;}}}
}void restore(int x) {vector<int> res;for (int v = x; v != -1; v = p[v]) {res.push_back(v);}std::reverse(res.begin(), res.end());for (int i = 0; i < res.size(); ++i) printf("%d", res[i]);puts("");
}

其中,

图的存储方式(链式前向星)

head[u] 和 e[i] 是链式前向星(一种图的邻接表存储方式)的关键部分:

  • head[u]:存储节点 u 的第一条边的编号(索引)。

  • e[i]:是一个结构体数组,存储第 i 条边的信息,通常包括:

    • e[i].to:这条边指向的节点(终点)。

    • e[i].nxt:下一条与 u 相连的边的编号(类似于链表中的 next 指针)

BFS应用

例题2-密室

问题 - 173B - Codeforces

一个n*m的图,现在有一束激光从左上角往右边射出,每遇到 '#',你可以选择光线往四个方向射出,或者什么都不做,问最少需要多少个 '#' 往四个方向射出才能使光线在第n行往右边射出。

此题目正解不是 0-1BFS,但是适用 0-1BFS,减小思维强度,赛时许多大佬都是这么做的。

做法很简单,一个方向射出不需要花费(0),而往四个方向射出需要花费(1),然后直接来就可以了。

#include <deque>
#include <iostream>
using namespace std;constexpr int INF = 1 << 29;
int n, m;
char grid[1001][1001];
int dist[1001][1001][4];
int fx[] = {1, -1, 0, 0};
int fy[] = {0, 0, 1, -1};
deque<int> q;  // 双端队列void add_front(int x, int y, int dir, int d) {  // 向前方加if (d < dist[x][y][dir]) {dist[x][y][dir] = d;q.push_front(dir);q.push_front(y);q.push_front(x);}
}void add_back(int x, int y, int dir, int d) {  // 向后方加if (d < dist[x][y][dir]) {dist[x][y][dir] = d;q.push_back(x);q.push_back(y);q.push_back(dir);}
}int main() {cin >> n >> m;for (int i = 0; i < n; i++) cin >> grid[i];for (int i = 0; i < n; i++)for (int j = 0; j < m; j++)for (int k = 0; k < 4; k++) dist[i][j][k] = INF;add_front(n - 1, m - 1, 3, 0);while (!q.empty()) {  // 具体搜索的过程,可以参考上面写的题解int x = q[0], y = q[1], dir = q[2];q.pop_front();q.pop_front();q.pop_front();int d = dist[x][y][dir];int nx = x + fx[dir], ny = y + fy[dir];if (nx >= 0 && nx < n && ny >= 0 && ny < m)add_front(nx, ny, dir, d);  // 判断条件if (grid[x][y] == '#')for (int i = 0; i < 4; i++)if (i != dir) add_back(x, y, i, d + 1);}if (dist[0][0][3] == INF)cout << -1 << endl;elsecout << dist[0][0][3] << endl;return 0;
}

习题

  • 「NOIP2017」奶酪

双端队列 BFS:

  • CF1063B. Labyrinth
  • CF173B. Chamber of Secrets
  • 「BalticOI 2011 Day1」打开灯泡 Switch the Lamp On

相关文章:

  • ExoPlayer 如何实现音画同步
  • CSS3 选择器完全指南:从基础到高级的元素定位技术
  • 2025年项目管理软件革命:AI与空间计算如何重塑企业协作格局
  • 国产化Word处理控件Spire.Doc教程:如何使用 C# 从 Word 中提取图片
  • 鸿蒙5.0项目开发——鸿蒙天气项目的实现(介绍)
  • 机器学习之AutoML:机器学习的自动化革命及其应用场景分析
  • CSS结构性伪类、UI伪类与动态伪类全解析:从文档结构到交互状态的精准选择
  • ssl 中 key 和pem 和crt是什么关系
  • 轻量级高性能推理引擎MNN 学习笔记 02.MNN主要API
  • 服务器相关
  • Linux之初见进程
  • LS-NET-012-TCP的交互过程详解
  • Qt应用程序启动时的一些思路:从单实例到性能优化的处理方案
  • 前端开发避坑指南:React 代理配置常见问题与解决方案
  • Mapreduce初使用
  • 集成钉钉消息推送功能
  • 基于开源AI大模型AI智能名片S2B2C商城小程序的零售结算技术创新研究——以京东AI与香港冯氏零售集团智能结算台为例
  • Linux中find命令用法核心要点提炼
  • 面试题:ReentrantLock与synchronized区别
  • 2025年RIS SCI2区,改进白鲸优化算法+复杂非线性方程组求解,深度解析+性能实测
  • 河南信阳拟发文严控预售许可条件:新出让土地开发的商品房一律现房销售
  • 在笔墨金石间,看胡问遂与梅舒适的艺术对话
  • 英国首相斯塔默一处房产发生火灾
  • 生态环境保护督察工作条例对督察对象和内容作了哪些规定?有关负责人答问
  • 国际博物馆日中国主会场确定,北京将展“看·见殷商”等展览
  • 75万采购防火墙实为299元路由器?重庆三峡学院发布终止公告:出现违法违规行为