【CSP】2021-09-3 脉冲神经网络 使用滚动数组代替map优化时间+常数级优化

本文主要是介绍【CSP】2021-09-3 脉冲神经网络 使用滚动数组代替map优化时间+常数级优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2021-09-3 脉冲神经网络 使用滚动数组代替map优化时间+常数级优化

首先说这题非常的恶心,算是一个垃圾题目,竟然卡的不是算法而是一些常数级优化,同样的算法可以拿到66分,而且同样的算法可以在acwing上过,但是csp的官方oj却有时候过有时候不过,很恶心,要是考试遇到了这种题目是不可能拿到100分的。

思路

这题的思路基本上所有人都能想到,和之前的第三题一样要建立索引。

首先我们解决这个题目一定是要遍历每个时刻,然后更新每个脉冲源和神经元的,然后可能会发出脉冲到突触(边)上,但是突触上脉冲的传播有时延,是在D个时间后,接收端才能接收到脉冲,所以这时候我们就要为每个神经元建立一个索引 用时间索引接受到脉冲的和(I[i][j] 表示i号神经元在j时刻接受到脉冲强度的总和),这样我们如果有脉冲到,可以直接加在对应的神经元的时间上,取的时候也可以直接取。

遇到的问题

  1. 使用double 做map的索引有问题

一开始没发现,用浮点数做索引会出现精度问题,就是同样是6.2 存储的时候有可能是6.19999999和6.20000001这样的然后判断索引的时候就取不到6.2索引对应的数据。后面改成int就好了

  1. 常数级优化

这题如果你是按照上边的思路写的,那么不出意外会只能拿到66分

在这里插入图片描述

会超时,因为题目时间限制是1s并且时间复杂度是 1 0 8 10^8 108所以我们需要一些常数级的优化(很恶心没见过卡这个的)。

  1. 将map换成二维数组

就是

struct neuron
{unordered_map<int, double> I;double v, u, a, b, c, d;int t;           // 表示neuron所处的时间
} nes[2001];         // 神经元

将里面的I提出出来

改成

double I[1005][1005];

这样就好了,并且由于时间是 1 0 5 10^5 105而神经元也有 1 0 3 10^3 103个这样就会导致超出空间限制

不知道为啥csp的oj报这个错误

在这里插入图片描述

然后使用滚动数组就好了

之后多提交几次就可以拿到时而83时而66的分数

在这里插入图片描述

  1. 其他的常数级优化

不使用万能头

// #include <bits/stdc++.h>
#include <iostream>
#include <cstring>
#include <vector>

使用 inline优化函数

inline int myrand(void)
{next1 = next1 * 1103515245 + 12345;return ((unsigned)(next1 / 65536) % 32768);
}

使用scanf printf 优化输入输出

    scanf("%d %d %d %d", &N, &S, &P, &T);scanf("%lf", &dt);printf("%.3f %.3f\n", min_v, max_v);printf("%d %d", min_times, max_times);

使用register优化循环

    for (register int i = 0; i < S; i++){struct link temp;int s;// cin >> s >> temp.t >> temp.w >> temp.D;scanf("%d %d %lf %d", &s, &temp.t, &temp.w, &temp.D);m[s].push_back(temp);mod = max(mod, temp.D + 1);// m[s][temp.t] = temp;}

然后就可以时而100分时而83分,但是acwing可以稳定拿到100分

在这里插入图片描述

完整代码

// #include <bits/stdc++.h>
#include <iostream>
#include <cstring>
#include <vector>using namespace std;
static unsigned long next1 = 1;
int N, S, P, T;
double dt;
struct neuron
{// unordered_map<int, double> I;// double I[2010];double v, u, a, b, c, d;int t;           // 表示neuron所处的时间
} nes[2001];         // 神经元
int out_times[2001]; // 发生脉冲的次数
int mod = 0;
double I[1005][1005];
struct link
{double w;int D;int t = -1;
};// 突触 注意第一个索引有可能大于等于N
// 如果大于等于N则为脉冲源
// unordered_map<int, vector<struct link>> m;
vector<struct link> m[2001];double r[2001]; // 脉冲源
/* RAND_MAX assumed to be 32767 */
inline int myrand(void)
{next1 = next1 * 1103515245 + 12345;return ((unsigned)(next1 / 65536) % 32768);
}signed main()
{// ios::sync_with_stdio(false);// cin.tie(0);// cout.tie(0);// cin >> N >> S >> P >> T;// cin >> dt;scanf("%d %d %d %d", &N, &S, &P, &T);scanf("%lf", &dt);int sum = 0;while (sum < N){int rn;double v, u, a, b, c, d;// cin >> rn >> v >> u >> a >> b >> c >> d;scanf("%d %lf %lf %lf %lf %lf %lf", &rn, &v, &u, &a, &b, &c, &d);for (register int i = 0; i < rn; i++){nes[sum + i].a = a, nes[sum + i].b = b, nes[sum + i].c = c, nes[sum + i].d = d;nes[sum + i].v = v, nes[sum + i].u = u;}sum += rn;}for (register int i = 0; i < P; i++){// cin >> r[i];scanf("%lf", &r[i]);}for (register int i = 0; i < S; i++){struct link temp;int s;// cin >> s >> temp.t >> temp.w >> temp.D;scanf("%d %d %lf %d", &s, &temp.t, &temp.w, &temp.D);m[s].push_back(temp);mod = max(mod, temp.D + 1);// m[s][temp.t] = temp;}int t = 0;while (t < T){t++;int t_tmp = t % mod;for (register int i = 0; i < P; i++) // 遍历脉冲源{// vector<struct link> temp = m[i + N];int rand = myrand();if (rand < r[i]){// for (int j = 0; j < N; j++)// {//     struct link item = m[i + N][j];//     if (item.t != -1)//         nes[item.t].I[t + item.D] += item.w;// }for (int j = 0; j < m[i + N].size(); j++){struct link item = m[i + N][j];I[(t_tmp + item.D) % mod][item.t] += item.w;// nes[item.t].I[t + item.D] += item.w;}}}for (register int i = 0; i < N; i++) //{nes[i].t = t;double v = nes[i].v, u = nes[i].u;nes[i].v = v + dt * (0.04 * v * v + 5 * v + 140 - u) + I[t_tmp][i];// nes[i].v = v + dt * (0.04 * v * v + 5 * v + 140 - u) + nes[i].I[t];// nes[i].I.erase(t);nes[i].u = u + dt * nes[i].a * (nes[i].b * v - u);if (nes[i].v >= 30){out_times[i]++;nes[i].v = nes[i].c;nes[i].u += nes[i].d;for (int j = 0; j < m[i].size(); j++){struct link item = m[i][j];I[(t_tmp + item.D) % mod][item.t] += item.w;// nes[item.t].I[t + item.D] += item.w;}}}memset(I[t_tmp], 0, sizeof I[t_tmp]);}double max_v = -1 * 1e8, min_v = 1e8;int max_times = -1, min_times = 1e5;for (register int i = 0; i < N; i++){max_v = max(nes[i].v, max_v);min_v = min(nes[i].v, min_v);max_times = max(out_times[i], max_times);min_times = min(out_times[i], min_times);}// cout << fixed << setprecision(3) << min_v << ' ' << max_v << endl;// cout << min_times << ' ' << max_times;printf("%.3f %.3f\n", min_v, max_v);printf("%d %d", min_times, max_times);return 0;
}

这篇关于【CSP】2021-09-3 脉冲神经网络 使用滚动数组代替map优化时间+常数级优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/822246

相关文章

RabbitMQ 延时队列插件安装与使用示例详解(基于 Delayed Message Plugin)

《RabbitMQ延时队列插件安装与使用示例详解(基于DelayedMessagePlugin)》本文详解RabbitMQ通过安装rabbitmq_delayed_message_exchan... 目录 一、什么是 RabbitMQ 延时队列? 二、安装前准备✅ RabbitMQ 环境要求 三、安装延时队

Python ORM神器之SQLAlchemy基本使用完全指南

《PythonORM神器之SQLAlchemy基本使用完全指南》SQLAlchemy是Python主流ORM框架,通过对象化方式简化数据库操作,支持多数据库,提供引擎、会话、模型等核心组件,实现事务... 目录一、什么是SQLAlchemy?二、安装SQLAlchemy三、核心概念1. Engine(引擎)

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

C# LiteDB处理时间序列数据的高性能解决方案

《C#LiteDB处理时间序列数据的高性能解决方案》LiteDB作为.NET生态下的轻量级嵌入式NoSQL数据库,一直是时间序列处理的优选方案,本文将为大家大家简单介绍一下LiteDB处理时间序列数... 目录为什么选择LiteDB处理时间序列数据第一章:LiteDB时间序列数据模型设计1.1 核心设计原则

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

使用shardingsphere实现mysql数据库分片方式

《使用shardingsphere实现mysql数据库分片方式》本文介绍如何使用ShardingSphere-JDBC在SpringBoot中实现MySQL水平分库,涵盖分片策略、路由算法及零侵入配置... 目录一、ShardingSphere 简介1.1 对比1.2 核心概念1.3 Sharding-Sp

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Java 正则表达式的使用实战案例

《Java正则表达式的使用实战案例》本文详细介绍了Java正则表达式的使用方法,涵盖语法细节、核心类方法、高级特性及实战案例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、正则表达式语法详解1. 基础字符匹配2. 字符类([]定义)3. 量词(控制匹配次数)4. 边