【题解】P1038 神经网络

【题解】P1038 神经网络

题面指路 P1038 [NOIP2003 提高组] 神经网络

一眼图论

大家好像都是用的拓扑排序

看到公式之后感觉这道题挺适合反向建边来做

即,从输出层开始向输出层递归,每一个点在递归的时候都加上所有可以到达该点的神经返回的信号值(如果能返回的话

并进行了一些优化(因为一个点一旦输出信号值不是零就代表这个点已经跑过了,可以直接返回该点输出信号值)

//一些基础配置
const int maxN = 150;
//这里是懒得想大概会有多少条边了就往大开了
const int maxE = (1e6+50);

struct Node{
	int inn,oun;
	int val,u;
}node[maxN];

int head[maxN];
int tot;

struct Edge{
    //注意,这里的所有信息都是反向建边的信息
    //即u代表输出点,to代表输入点(同时代表上一条边)
	int u,nxt,to,w;
}edge[maxE];

void add_edge(int u,int v,int w){
	edge[++tot].u = u;
	edge[tot].to = v;
	edge[tot].w = w;
	edge[tot].nxt = head[u];
	head[u] = tot;
}
int Search(int k){
	int eid = k;
    //一点优化,如果这个点是输入层的点,就不需要减去权重直接返回
    //由于题目保证非输入层的神经元初始状态必为零
    //所以可以通过当前点的信号强度是否为零判断该点是否更新过
	if(node[eid].val != 0) return node[eid].val;
	if(node[eid].inn == 0) return node[eid].val;
	for(int i = head[eid];i;i = edge[i].nxt){
		int to_ = edge[i].to;
		int un = edge[i].u;
		int t = Search(to_);
        //平静状态神经元不传递信号
		if(t <= 0) continue;
        //更新该神经元的信号强度
		node[un].val +=  t * edge[i].w;
	}
    //减去该点权值
	node[k].val -= node[k].u;
	return node[k].val;
}
int main(){
	scanf("%d%d",&n,&p);
	for(int i = 1;i<=n;i++){
		int sta,u;
		scanf("%d%d",&sta,&u);
		node[i].val = sta;
		node[i].u = u;
		node[i].oun = 0;//统计出度
		node[i].inn = 0;//统计入度
	}
	for(int i = 0;i<p;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		node[u].oun++;node[v].inn++;//统计入度与出度(原图的信息)
		add_edge(v,u,w);//反向建边
	}
	int flg = 1;
	for(int i = 1;i<=n;i++){
        //判断是不是输出层,应该从输出层中的点开始往回找
		if(node[i].oun != 0) continue;
        
		int t = Search(i);
        //由于输出层也可能出现平静状态神经元所以要判断一下
		if(t <= 0) continue;
        
		printf("%d %d\n",i,node[i].val);
		flg = 0;
	}
	if(flg) printf("NULL");
	return 0;
}

点此查看完整代码

posted @ 2022-03-28 23:36  Burnling  阅读(81)  评论(0编辑  收藏  举报