[NOIP2003 提高组] 神经网络/n/n## 题目背景/n/n人工神经网络(Artificial Neural Network)是一种新兴的具有自我学习能力的计算系统,在模式识别、函数逼近及贷款风险评估等诸多领域有广泛的应用。对神经网络的研究一直是当今的热门方向,兰兰同学在自学了一本神经网络的入门书籍后,提出了一个简化模型,他希望你能帮助他用程序检验这个神经网络模型的实用性。/n/n## 题目描述/n/n在兰兰的模型中,神经网络就是一张有向图,图中的节点称为神经元,而且两个神经元之间至多有一条边相连,下图是一个神经元的例子:/n/n/n/n神经元〔编号为 $i$)/n/n/n图中,$X_1 /sim X_3$ 是信息输入渠道,$Y_1 /sim Y_2$ 是信息输出渠道,$C_i$ 表示神经元目前的状态,$U_i$ 是阈值,可视为神经元的一个内在参数。/n/n神经元按一定的顺序排列,构成整个神经网络。在兰兰的模型之中,神经网络中的神经元分为几层;称为输入层、输出层,和若干个中间层。每层神经元只向下一层的神经元输出信息,只从上一层神经元接受信息。下图是一个简单的三层神经网络的例子。/n/n/n/n兰兰规定,$C_i$ 服从公式:(其中 $n$ 是网络中所有神经元的数目)/n/n$$C_i=//left(//sum//limits_{(j,i) //in E} W_{ji}C_{j}//right)-U_{i}$$/n/n公式中的 $W_{ji}$(可能为负值)表示连接 $j$ 号神经元和 $i$ 号神经元的边的权值。当 $C_i$ 大于 $0$ 时,该神经元处于兴奋状态,否则就处于平静状态。当神经元处于兴奋状态时,下一秒它会向其他神经元传送信号,信号的强度为 $C_i$。/n/n如此.在输入层神经元被激发之后,整个网络系统就在信息传输的推动下进行运作。现在,给定一个神经网络,及当前输入层神经元的状态($C_i$),要求你的程序运算出最后网络输出层的状态。/n/n## 输入格式/n/n输入文件第一行是两个整数 $n$($1 //le n //le 100$)和 $p$。接下来 $n$ 行,每行 $2$ 个整数,第 $i+1$ 行是神经元 $i$ 最初状态和其阈值($U_i$),非输入层的神经元开始时状态必然为 $0$。再下面 $p$ 行,每行有两个整数 $i,j$ 及一个整数 $W_{ij}$,表示连接神经元 $i,j$ 的边权值为 $W_{ij}$。/n/n## 输出格式/n/n输出文件包含若干行,每行有 $2$ 个整数,分别对应一个神经元的编号,及其最后的状态,$2$ 个整数间以空格分隔。仅输出最后状态大于 $0$ 的输出层神经元状态,并且按照编号由小到大顺序输出。/n/n若输出层的神经元最后状态均小于等于 $0$,则输出 NULL。/n/n## 样例 #1/n/n### 样例输入 #1/n/n/n5 6/n1 0/n1 0/n0 1/n0 1/n0 1/n1 3 1/n1 4 1/n1 5 1/n2 3 1/n2 4 1/n2 5 1/n/n/n### 样例输出 #1/n/n/n3 1/n4 1/n5 1/n/n/n## 提示/n/n**【题目来源】**/n/nNOIP 2003 提高组第一题/n/n## 算法思路/n/n这道题的核心在于对神经网络的模拟,我们可以采用拓扑排序的思想来解决问题。具体思路如下:/n/n1. 构建图: 根据输入数据,构建一个有向图,节点代表神经元,边代表连接关系,边上的权值即为 $W_{ij}$。/n/n2. 拓扑排序: 对构建的图进行拓扑排序,得到神经元之间的依赖关系。/n/n3. 状态更新: 按照拓扑排序的顺序,逐个更新神经元的状态 $C_i$。对于每个神经元 $i$,遍历其所有入边,计算其所有前驱神经元状态的加权和,再减去阈值 $U_i$,得到当前神经元的状态。/n/n4. 输出结果: 最后,遍历所有输出层神经元,输出状态大于 0 的神经元及其状态。/n/n## 代码实现/n/ncpp/n#include <iostream>/n#include <vector>/n#include <queue>/nusing namespace std;/n/nstruct Neuron {/n int state;/n int threshold;/n vector<pair<int, int>> edges;/n Neuron() {/n state = 0;/n threshold = 0;/n }/n};/n/nint main() {/n int n, p;/n cin >> n >> p;/n vector<Neuron> neurons(n + 1);/n vector<int> inDegree(n + 1, 0);/n for (int i = 1; i <= n; i++) {/n cin >> neurons[i].state >> neurons[i].threshold;/n }/n for (int i = 0; i < p; i++) {/n int u, v, w;/n cin >> u >> v >> w;/n neurons[u].edges.push_back(make_pair(v, w));/n inDegree[v]++;/n }/n /n queue<int> q;/n for (int i = 1; i <= n; i++) {/n if (inDegree[i] == 0) {/n q.push(i);/n }/n }/n /n while (!q.empty()) {/n int cur = q.front();/n q.pop();/n for (pair<int, int> edge : neurons[cur].edges) {/n int next = edge.first;/n int weight = edge.second;/n neurons[next].state += weight * neurons[cur].state;/n inDegree[next]--;/n if (inDegree[next] == 0) {/n q.push(next);/n }/n }/n }/n /n vector<pair<int, int>> outputNeurons;/n for (int i = 1; i <= n; i++) {/n if (neurons[i].state > 0 && neurons[i].edges.empty()) {/n outputNeurons.push_back(make_pair(i, neurons[i].state));/n }/n }/n /n if (outputNeurons.empty()) {/n cout << /'NULL/' << endl;/n } else {/n for (pair<int, int> neuron : outputNeurons) {/n cout << neuron.first << /' /' << neuron.second << endl;/n }/n }/n /n return 0;/n}/n/n/n## 代码解析/n/n1. 数据结构:/n - Neuron 结构体:存储每个神经元的状态、阈值和连接的边。/n - inDegree 数组:记录每个神经元的入度,用于拓扑排序。/n/n2. 构建图:/n - 读取输入数据,将神经元和连接关系存储到 neurons 数组和 inDegree 数组中。/n/n3. 拓扑排序:/n - 使用队列 q 实现拓扑排序。/n - 将所有入度为 0 的神经元加入队列。/n - 循环遍历队列,取出队首元素,更新其所有后继神经元的状态,并将后继神经元的入度减 1,如果入度为 0,则将其加入队列。/n/n4. 状态更新:/n - 在拓扑排序过程中,遍历每个神经元的所有入边,计算其所有前驱神经元状态的加权和,再减去阈值,更新当前神经元的状态。/n/n5. 输出结果:/n - 遍历所有输出层神经元,输出状态大于 0 的神经元及其状态。/n - 如果所有输出层神经元状态均小于等于 0,则输出 NULL。/n/n## 总结/n/n本文通过详细的讲解和代码示例,展示了如何利用拓扑排序解决 NOIP2003 提高组第一题“神经网络”。希望这篇文章能帮助你理解神经网络模型的构建和运行过程,并掌握拓扑排序的应用技巧。/n

NOIP2003 提高组 神经网络 - 算法详解及代码实现

原文地址: https://www.cveoy.top/t/topic/vbD 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录