D152 拓扑排序 P1038 [NOIP 2003 提高组] 神经网络

D152 拓扑排序 P1038 [NOIP 2003 提高组] 神经网络_哔哩哔哩_bilibili

 

P1038 [NOIP 2003 提高组] 神经网络 - 洛谷

一个分层的有向无环图,n 个点,m 条边,每个点都有两个属性 $C_i$ 和 $U_i$,传递关系 $C_i=(\sum{W_{ji}*C_j})-U_i,\;C_j>0$,求输出层的 $C_i>0$ 的点

思路

既然是研究有向无环图的传递问题,自然是拓扑排序,如何建图呢?

除了记录入度数组,还要记录出度数组,用来判是否输出层的点,因为输出层的出度 $=0$

在拓扑开始时,把输入层的点均入队,其他层的点先减去阈值 $U_i$

然后,跑拓扑排序,累计各点的 $C_i$ 值。最后,按条件输出

相关板子:

D01【模板】拓扑排序 - 董晓 - 博客园

 

// 拓扑排序 O(n)
#include<bits/stdc++.h>
using namespace std;

const int N=105;
vector<pair<int,int>> e[N];
int n,m;
int C[N],U[N],rd[N],cd[N];

void topo(){
  queue<int> q;
  for(int i=1; i<=n; i++){
    if(rd[i]==0) q.push(i); //输入层的点均入队 
    else C[i]-=U[i]; //其他层先减阈值Ui(点权)
  } 
  while(!q.empty()){
    int u=q.front(); q.pop();
    for(auto [v,w]:e[u]){
      if(C[u]>0) C[v]+=C[u]*w; //如果u点能兴奋,则向v点发送信号C[u]
      if(--rd[v]==0) q.push(v);
    }
  }
}
int main(){
  cin>>n>>m; //n个神经元 m条边
  for(int i=1;i<=n;i++) cin>>C[i]>>U[i]; //每个点的最初状态和阈值
  for(int i=1,u,v,w; i<=m; i++){
    cin>>u>>v>>w; //从点u到点v的边权w
    e[u].emplace_back(v,w);
    cd[u]++; //u的出度+1
    rd[v]++; //v的入度+1
  }
  topo();
  
  bool ok=0;
  for(int i=1;i<=n;i++)if(!cd[i]&&C[i]>0){ //如果是输出层且状态>0的点
    cout<<i<<" "<<C[i]<<"\n",ok=1;
  }
  if(!ok) cout<<"NULL";
}

 

posted @ 2026-05-02 18:44  董晓  阅读(61)  评论(0)    收藏  举报