2021.12.19~12.20 练习CSP 202109-3 脉冲神经网络
本题的实现参考链接:大佬的100分脉冲神经网络代码
练习过程中遇到的困难:
- 对于脉冲经过突触的传递机制认识不足,I_k数组的设计值得考虑.
- 对于题目中这句话 “保证所有的RN加起来等于N。它们从前向后按编号顺序描述神经元,每行对应一段连续编号的神经元的信息” 的理解不到位.
-
”脉冲源在每个时刻以一定的概率发放一个脉冲,模拟这个过程的伪随机函数“ 题目中已给,然而它的变量设计为
next
,将代码提交到Acwing网站上测试时,出现reference to ‘next’ is ambiguous
的错误,以后注意定义的变量尽量避免关键字名称。本文给出的代码已将变量next
更名为nnext
.
一开始将N个节点的输入代码设计如下:(错误示例)
int temp_N=N;
int N_tmp=0;
while(temp_N>0)
{
cin>>RN;
temp_N-=RN;
while(RN>0)
{
cin>>Node[N_tmp].v>>Node[N_tmp].u>>Node[N_tmp].a>>Node[N_tmp].b>>Node[N_tmp].c>>Node[N_tmp].d;
N_tmp++;
RN--;
}
}
由于,当RN>1时,输入的节点参数信息需要分配给RN个不同神经元,故以上代码是错误的,更正如下:
int temp_N=N;
int N_tmp=0;
while(temp_N>0)
{
int RN;
cin>>RN;
temp_N-=RN;
int RN_tmp=RN;
double v,u,a,b,c,d;
cin>>v>>u>>a>>b>>c>>d;
while(RN_tmp>0)
{
Node[N_tmp].v=v;
Node[N_tmp].u=u;
Node[N_tmp].a=a;
Node[N_tmp].b=b;
Node[N_tmp].c=c;
Node[N_tmp].d=d;
N_tmp++;
RN_tmp--;
}
}
最终提交的代码只获得66分,原因是运行超时,在此估计运行超时的原因在于I_k数组的设计方法,依次遍历不同的突触耗时过长,先将66分代码贴在下面,今后再做修改完善:
#include<bits/stdc++.h>
using namespace std;
const int max_num=2010;
const double INF=1e8;
int N,S,P,T;
double t1;
double I_k[max_num][max_num];
//神经元个数
struct node
{
double v,u,a,b,c,d;
int count_put;
}Node[max_num];
struct tuchu
{
int D;
double s,t,w;
}Tuchu[max_num];
static unsigned long nnext = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
nnext = nnext * 1103515245 + 12345;
return((unsigned)(nnext/65536) % 32768);
}
int main()
{
cin>>N>>S>>P>>T;
cin>>t1;
int temp_N=N;
int N_tmp=0;
while(temp_N>0)
{
int RN;
cin>>RN;
temp_N-=RN;
int RN_tmp=RN;
double v,u,a,b,c,d;
cin>>v>>u>>a>>b>>c>>d;
while(RN_tmp>0)
{
Node[N_tmp].v=v;
Node[N_tmp].u=u;
Node[N_tmp].a=a;
Node[N_tmp].b=b;
Node[N_tmp].c=c;
Node[N_tmp].d=d;
N_tmp++;
RN_tmp--;
}
}
int maic[max_num];
int P_tmp=0;
int temp_P=P;
while(temp_P>0)
{
int r;
cin>>r;
maic[P_tmp+N]=r;
P_tmp++;
temp_P--;
}
int S_tmp=0;
int temp_S=S;
int mod=0;
while(temp_S>0)
{
int D;
double s,t,w;
cin>>s>>t>>w>>D;
Tuchu[S_tmp].s=s;
Tuchu[S_tmp].t=t;
Tuchu[S_tmp].w=w;
Tuchu[S_tmp].D=D;
mod=max(mod,Tuchu[S_tmp].D+1);//!!!
temp_S--;
S_tmp++;
}
//-----------输入完毕-------------
for(int i=0;i<T;i++)
{
int t_tmp=i % mod;//!!!
for (int j=N;j<P+N;j++)
{
if(maic[j]>myrand())
//如果该时刻此脉冲源的r>myrand(),找到与其连接的神经元
//该神经元的该时刻+D的IK要接收到脉冲
{
for(int m=0;m<S;m++)//查看有没有与该脉冲源相关的突触
{
if(Tuchu[m].s==j)//如果该突触的入节点正好是该脉冲源
{
int node_get=Tuchu[m].t;//记录该突触出节点的序号
double w_tmp=Tuchu[m].w;
int D_tmp=Tuchu[m].D;
I_k[(t_tmp+D_tmp)%mod][node_get]+=w_tmp;
}
}
}
}
for (int j=0;j<N;j++)
{
double v_tmp=Node[j].v;
double u_tmp=Node[j].u;
double a_tmp=Node[j].a;
double b_tmp=Node[j].b;
double c_tmp=Node[j].c;
double d_tmp=Node[j].d;
Node[j].v=v_tmp+t1*(0.04*v_tmp*v_tmp+5*v_tmp+140-u_tmp)+I_k[t_tmp][j];
Node[j].u=u_tmp+t1*a_tmp*(b_tmp*v_tmp-u_tmp);
if(Node[j].v>=30)
{
Node[j].v=c_tmp;
Node[j].u+=d_tmp;
Node[j].count_put++;
for(int m=0;m<S;m++)//查看有没有与该神经元相关的突触
{
if(Tuchu[m].s==j)//如果该突触的入节点正好是该神经元
{
int node_get=Tuchu[m].t;//记录该突触出节点的序号
double w_tmp=Tuchu[m].w;
int D_tmp=Tuchu[m].D;
I_k[(t_tmp+D_tmp)%mod][node_get]+=w_tmp;
}
}
}
//cout<<I_k[t_tmp][j]<<" "<<Node[j].v<<" "<<Node[j].u<<endl;
}
memset( I_k[t_tmp], 0, sizeof I_k[t_tmp]);//!!!
}
double max_v=-INF;
double min_v=INF;
int max_count=-INF;
int min_count=INF;
for (int i=0;i<N;i++)
{
max_v=max(max_v,Node[i].v);
min_v=min(min_v,Node[i].v);
max_count=max(max_count,Node[i].count_put);
min_count=min(min_count,Node[i].count_put);
}
cout<<setiosflags(ios::fixed)<<setprecision(3)<<min_v<<" "<<max_v<<endl;
cout<<min_count<<" "<<max_count<<endl;
return 0;
}
提交结果如下,66分的代码见上,33分的代码仅将上面的代码max_num改为了1005,也就是我最初设置的值,后面参考文章最上方找到的参考代码将max_num设置为2010,就多了33分。(说实话我还是没懂为什么1005不行,因为题目给的数据限制是1000,如果有大佬知道,恳请评论区告诉我,感激不尽!)
依然存在疑惑的点:
- mod的设置:
mod=max(mod,Tuchu[S_tmp].D+1);
- 时间
t_tmp
的设置:int t_tmp=i % mod;
-
I_k
数组的设置:memset( I_k[t_tmp], 0, sizeof I_k[t_tmp]);//!!!
将这两天的解题经历先记录在此,本题还有待持续的思考和优化。