洛谷的测试数据仅供民间交流使用,非官方测试数据。官方评测链接:https://www.cspro.org/。
在本题中,你需要实现一个 SNN(spiking neural network,脉冲神经网络)的模拟器。一个 SNN 由以下几部分组成:
- 神经元:按照一定的公式更新内部状态,接受脉冲并可以发放脉冲
- 脉冲源:在特定的时间发放脉冲
- 突触:连接神经元-神经元或者脉冲源-神经元,负责传递脉冲
神经元会按照一定的规则更新自己的内部状态。本题中,我们对时间进行离散化处理,即设置一个时间间隔 ,仅考虑时间间隔整数倍的时刻 ,按照下面的公式,从 时刻的取值计算 时刻的变量的取值:
其中 和 是神经元内部的变量,会随着时间而变化, 和 是常量,不会随着时间变化;其中 表示该神经元在 时刻接受到的所有脉冲输入的强度之和,如果没有接受到脉冲,那么 。当进行上面的计算后,如果满足 ,神经元会发放一个脉冲,脉冲经过突触传播到其他神经元;同时, 设为 并且 设为 ,其中 和 也是常量。图 1 展示了一个神经元 变量随时间变化的曲线。
:::align{center}
:::
突触表示的是神经元-神经元、脉冲源-神经元的连接关系,包含一个入结点和一个出结点(可能出现自环和重边)。当突触的入结点(神经元或者脉冲源)在 时刻发放一个脉冲,那么在传播延迟 个时刻以后,也就是在 时刻突触的出结点(神经元)会接受到一个强度为 的脉冲。
脉冲源在每个时刻以一定的概率发放一个脉冲,为了模拟这个过程,每个脉冲源有一个参数 ,并统一采用以下的伪随机函数:
C++ 版本:
static unsigned long next = 1;
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
Python 版本:
next = 1
def myrand():
global next
next = (next * 1103515245 + 12345) % (2 ** 64)
return (next // 65536) % 32768
Java 版本:
long next = 1;
int myrand() {
next = next * 1103515245 + 12345;
return (int)((Long.divideUnsigned(next, 65536)) % 32768);
}
在每个时刻,按照编号顺序从小到大,每个脉冲源调用一次上述的伪随机函数,当 时,在当前时刻发放一次脉冲,并通过突触传播到神经元。
进行仿真的时候,已知 0 时刻各个神经元的状态,从 1 时刻开始按照上述规则进行计算,直到完成 时刻的计算,再输出 时刻神经元的 值和发放的脉冲次数分别的最小值和最大值。
规定输入数据中结点按如下方式顺序编号: 为神经元的编号, 为脉冲源的编号。
代码中请使用双精度浮点类型。