P1038 神经网络 题解

神经网络

题意

\(n\) 个节点和 \(p\) 条边。

每个节点可以长成这样:

每个节点都有一个内在参数 \(u_i\),还有一个状态 \(c_i\)

节点按照一定顺序排列,可分为三种类型:输入层,中间层和输出层,每个节点只可从上一层接受信息,向下一层传递信息。

对于每个点的状态,有以下公式:

\[c_i=\left(\sum\limits_{(j,i) \in E} w_{j,i}\times c_{j}\right)-u_{i} \]

其中 \(w_{j,i}\) 为一条从节点 \(j\) 转移到节点 \(i\) 的边上的边权。

\(c_i > 0\) 时,该节点可以向它连向的节点发送信号,否则就不行。


给定了每个节点的初始状态和内在参数,\(p\) 条有向边从 \(x_i\) 连向 \(y_i\),边权为 \(w_{x_i,y_i}\)

不是输入层的节点初始状态一定为 \(0\)

请求出所有 \(c_i>0\) 的输出层节点的编号还有最终状态(就是 \(c_i\)),如果没有则输出 NULL

数据范围

  • \(1 \leqslant n \leqslant 100\)
  • 两个节点直接最多只有一条边

思路

很明显,这里不会有环和重边,拓扑序也可以轻松发现。

那么这题就是拓扑排序的天下了,在求拓扑序的同时去求一下 \(c_i\) 即可。

细节

1 公式

只有 \(c_i > 0\) 时才可以向其他点发送信号,同理也只有当 \(c_j > 0\) 时才可以从这个点接收信号

也就是说,公式可以变成这样:

\[c_i=\left(\sum\limits_{(j,i) \in E,c_j>0} w_{j,i} \times c_{j}\right)-u_{i} \]

2 逻辑

题意中有一个逻辑坑点:

不是输入层的节点初始状态一定为 \(0\)

并没有说输入层的节点初始状态一定不为 \(0\),所以要稍加小心(只是代码逻辑问题,对答案并不能产生影响,因为输入层节点初始状态若为 \(0\),那么也是不可以向下一层传输信号的)

3 分类

输入层的节点不参与公式计算,即不会减去内在参数。

复杂度

  • 时间:\(O(n+m)\)
  • 空间:\(O(n+m)\)

Code

点击查看代码
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

struct node {
  int f, u;
} a[110];
struct Node {
  int x, y;
};

int n, m, ansf, x, y, z, b[110], c[110];
vector<Node> v[110];

void dfs (int x) {
  b[x]--; // 相当于一种标记
  if (!a[x].f) { // 不是输入层
    c[x] -= a[x].u; // 减去内在参数
  }
  for (auto i : v[x]) {
    b[i.x]--;
    if (c[x] > 0) { // 只有当前点的ci>0时才可以发送信号
      c[i.x] += c[x] * i.y; // 公式套上
    }
    if (!b[i.x]) { // 这个点计算完了
      dfs(i.x); // 调用一下
    }
  }
}

int main(){
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> a[i].f >> a[i].u; // 初始状态和内在参数
  }
  for (int i = 1; i <= m; i++) {
    cin >> x >> y >> z;
    v[x].push_back({y, z}); // 边
    b[y]++;
  }
  for (int i = 1; i <= n; i++) {
    if (a[i].f) { // 输入层
      c[i] = a[i].f;
      dfs(i);
    }
  }
  for (int i = 1; i <= n; i++) {
    if (!v[i].size() && c[i] > 0) { // 输出层且满足要求
      cout << i << ' ' << c[i] << '\n'; // 输出一下
      ansf = 1; // 标记有答案
    }
  }
  if (!ansf) { // 没有答案,输出NULL
    cout << "NULL";
  }
  return 0;
}
posted @ 2023-03-14 12:30  wnsyou  阅读(26)  评论(0编辑  收藏  举报