NOIP2003提高组之神经网络

1/**//*
  2=========程序信息========
  3对应题目:noip2003提高组_神经网络
  4使用语言:c++
  5使用编译器:dev c++
  6使用算法:模拟
  7算法运行时间:O(n^2 * layer) 其中layer为层数,最大为n。[明显这个神经网络是一个稀疏图,如果改用链表存储方法存储图的边的话将大大减小运行时间。]
  8作者:贵州大学05级 刘永辉 
  9昵称:SDJL
 10编写时间:2008年8月
 11联系QQ:44561907
 12E-Mail:44561907@qq.com
 13获得更多文章请访问我的博客:www.cnblogs.com/sdjl
 14如果发现BUG或有写得不好的地方请发邮件告诉我:)
 15=========题目解析========
 16题目补充点一:题目中出现的那个公式中有一个向又开口的符号(下面用“E”表示),那个是求和符号,在此题中表示第i个神经原的C值等于所有   指向第i个神经元的边的W值乘于发出信号的神经元的C值  的和,最后在减去第i个神经元的U值,注意U在整个公式中仅减一次(刚接触E符号的人会把Ewc-u理解为E(wc - u),事实上应该是E(wc) - u)。
 18  这是一个模拟题,因为信号是一层一层地传递的,所以我们可以仅关心当前的发送层有哪些神经元,以及接收信号层有哪些神经元.并且每一个神经元仅有一次机会进入发送层,同 样也仅有一次机会进入接收层,在一个神经元进入接收层后下一秒它必定将进入发送层(注意:进入发送层不一定就会发送信号,当神经元处于平静状态时它是不会发送信号的,但它依然属于发送层!)。
 19在读取数据后,依据题目可以根据c[i]是否大于0来判断初始时哪些神经元属于发送层。
 20我们用senderLayer[i]==true表示第i个元素属于发送层的神经元,用incepterLayer[i]==true表示第i个元素属于接收层的神经元,当接收层中的神经元数大于0时,表示神经信号传递的过程还没有结束,此时我们要利用题目给出的公式计算接受层中每一个神经元的状态值,直到接收层中的神经元数为0时信号传递过程结束,程序结束。
 21*/
 23
 24//=================代码如下================
 25#include <cstdlib>
 26#include <iostream>
 27#include <fstream>
 29using namespace std;
 31const int maxn = 200;//最大神经元数目
 32int n;//神经元数目
 33int w[maxn][maxn];//w[i][j]为第i个神经元与第j个神经元之间边的权值
 34int c[maxn];//神经元的状态,当c[i]>0时第i个神经元处于兴奋状态,下一秒它会向其他神经元传送信号,信号的强度为Ci
 35int u[maxn];//u[i]是阈值,可视为神经元的一个内在参数,在公式中有用
 36bool senderLayer[maxn];//senderLayer[i]==true表示第i个元素属于发送层的神经元
 37bool incepterLayer[maxn];//incepterLayer[i]==true表示第i个元素属于接收层的神经元
 39//初始化数据
 40void init()
 41{     
   //初始化w为0============================    
       for(int i=0; i<maxn; i++)
        for(int j=0; j<maxn; j++)
            w[i][j] = 0;
 47    //初始化c、u为零,清空发送层与接收层中的神经元==============================
    for(int i=0; i<maxn; i++)
    {
       c[i] = 0;
       u[i] = 0;        
       senderLayer[i] = false;
       incepterLayer[i] = false;
    }     
    
    //读取数据c、u,并初始化发送层神经元=====================================
    ifstream inputFile("network.in");//输入文件名为network.in
    int p;//边数,与题目对应 
    //[编程风格提示:p的定义不要和n写在一起,n是全局都回使用到的一个值,而p仅在读取边数时有用,变量的定义应该接近第一次使用它的地方]
    inputFile>>n>>p;
    for(int i=0; i<n; i++)
    {
       inputFile>>c[i]>>u[i];
 65        /**//*
       如果神经元处于兴奋状态,则把神经元加入接收层.注意:按理来说我们此时因该把第i个神经元加入发送层,而不是接收层,
       但是这并不是笔误,之所以是incepterLayer[i] = true而不是senderLayer[i] = true是有原因的,你可以暂时不用管,
       看到下面的代码时我会解释,我们先把这里假设为谜团一!
       */
       if(c[i]>0)            
           incepterLayer[i] = true;        
    }
 74     //读取边权值===============================================
        int i,j;
    for(int k=0; k<p; k++)
    {
       inputFile>>i>>j;
       inputFile>>w[i-1][j-1];//题目是从1开始编号,而我们编程从0开始编号,所以减去1
    }
    
    inputFile.close();
    
 84}
 86/**//*
 87获取下一秒发送层与接收层中的神经元,并且返回下一秒接收层中神经元的个数,这个返回值用于判断模拟过程是否结束
 88[编程风格提示1:这里GetIncepterLayer方法从名字上来看它仅计算出了接收层中的神经元,而实际上它同时计算了发送层的神经元,因此GetSenderLayerAndIncepterLayer也许会更加准确,但是这个名字太长了!]
 89[编程风格提示2:这里GetIncepterLayer不但获得了两个层中的神经元,还同时计算并返回了接收层中神经元数,这是一种不好的设计,按道理来说,我们因该遵守一个方法一个职责的原则,而这里的GetIncepterLayer具有了两个原则。]
 90*/
 91int GetIncepterLayer()
 92{
   //下一秒的发送层等于上一秒的接收层,而下一秒的接收层暂时为空=======================
   for(int i=0; i<n; i++)
   {
       senderLayer[i] = incepterLayer[i];
       incepterLayer[i] = false;
   }    
100
   int incepterLayerCount = 0;    //下一秒的接收层中神经元个数
   //计算下一秒中神经元
   for(int i=0; i<n; i++)
   {
       if(senderLayer[i] == true)
           {
               for(int j=0; j<n; j++)
                   if(w[i][j]>0)
                   {
                       incepterLayer[j] = true;
                       incepterLayerCount++;
                   }
           }
   }
   
   return incepterLayerCount;
117}
119//运行信号传递模拟过程
120void run()
121{
   //如果下一秒钟接收层中神经元不为空时继续传递信号
   //注意:当第一次调用GetIncepterLayer时发生了什么?发送层初始如何?结束时如何?接收层初始如何?结束时又如何?想一想就知道谜团一了!
   while(GetIncepterLayer() > 0)
   {
       //j是发送层中的神经元,i是接收层中的神经元,与题目对应
       for(int j=0; j<n; j++)
           for(int i=0; i<n; i++)
               //如果j在发送层中,i在接收层中,且j处于兴奋状态
               if(   (senderLayer[j] == true) && (incepterLayer[i] == true) && (c[j]>0)   )
               {
                   c[i] += w[j][i] * c[j];    
               }    
       
       for(int i=0; i<n; i++)
           if(incepterLayer[i] == true)
               c[i] -= u[i];
   }    
139}
141//显示数据(输出到屏幕)
142void show()
143{
   bool nullAnswer = true;
   for(int i=0; i<n; i++)
       if((senderLayer[i] == true) && (c[i] > 0))
       {
           cout<<i+1<<' '<<c[i]<<endl;//输出编号时记得加1,这是因为编程从0开始编号
           nullAnswer = false;
       }
   
   if(nullAnswer == true )
       cout<<"NULL";
154}
156//主函数调用
157int main(int argc, char *argv[])
158{
160    init();//初始化数据,从文件network.in中读入全局变量数据n、w、c、u,以及计算出初始发送层
   run();//进行模拟过程
   show();//显示数据(输出到屏幕)
   system("PAUSE");
   return EXIT_SUCCESS;
165}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值