CSP 202109-3 脉冲神经网络练习笔记

2021.12.19~12.20 练习CSP 202109-3 脉冲神经网络

本题的实现参考链接:大佬的100分脉冲神经网络代码

练习过程中遇到的困难:

  1. 对于脉冲经过突触的传递机制认识不足,I_k数组的设计值得考虑.
  2. 对于题目中这句话 “保证所有的RN加起来等于N。它们从前向后按编号顺序描述神经元,每行对应一段连续编号的神经元的信息” 的理解不到位.
  3. ”脉冲源在每个时刻以一定的概率发放一个脉冲,模拟这个过程的伪随机函数“ 题目中已给,然而它的变量设计为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,如果有大佬知道,恳请评论区告诉我,感激不尽!)
CSP 202109-3 脉冲神经网络练习笔记
依然存在疑惑的点:

  1. mod的设置:mod=max(mod,Tuchu[S_tmp].D+1);
  2. 时间t_tmp的设置:int t_tmp=i % mod;
  3. I_k数组的设置:memset( I_k[t_tmp], 0, sizeof I_k[t_tmp]);//!!!

将这两天的解题经历先记录在此,本题还有待持续的思考和优化。

上一篇:ant通用模板(build_common.xml)使用介绍


下一篇:oracle 函数