Yurchiu's Blog

P1038 神经网络

Yurchiu 2020-01-13, 20:04:39 1.1k 隐藏左右两栏 展示左右两栏

P1038 神经网络 的题解。

code

先 po ​一下​ code\color{red}{\tt\text{code}}:

#include<bits/stdc++.h>
#define _ 0
using namespace std;
struct edge
{
	int nxt,end,len;
}e[100*100+5];
int n,p,head[100+5],cnt=0,outf=1; 
int c[100+5],u[100+5],type[100+5],v[100+5][100+5];
queue<int>q;
inline void add(int x,int y,int l)//喜闻乐见的链式前向星
{
	e[++cnt]=(edge){head[x],y,l};
	head[x]=cnt;
	return;		
}
void bfs()
{
	for(int i=1;i<=n;i++)
		if(type[i]==1)
			q.push(i);
	while(!q.empty())
	{
		bool flag=1;
		int now=q.front();
		q.pop();
		if(!v[now][0])//v[i][0]==1表示这个神经元的C已运算完
		{
			if(type[now]!=1)
				c[now]-=u[now];//公式的后半部分,减去阈值
			v[now][0]=1;
		}
		for(int i=head[now];i;i=e[i].nxt)
		{
			int next=e[i].end;
			if(!v[next][0]&&!v[next][now]&&c[now]>0)
				c[next]+=e[i].len*c[now],v[next][now]=1;//v[i][...]打标记去重
			flag=0,q.push(next);
		}
		if(flag)
			type[now]=2;
	}
	return;
}
int main()
{
	scanf("%d%d",&n,&p);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&c[i],&u[i]);
		if(c[i]!=0)
			type[i]=1;
	}
	for(int i=1;i<=p;i++)
	{
		int t1,t2,t3;
		scanf("%d%d%d",&t1,&t2,&t3);//建图
		add(t1,t2,t3);
	}
	bfs();
	for(int i=1;i<=n;i++)
		if(type[i]==2&&c[i]>0)
			outf=0,printf("%d %d\n",i,c[i]);
	if(outf)//是否输出NULL
		printf("NULL");
	return ~~(0^_^0);//嘤嘤嘤 放心不会CE
}

思路

很清晰!依照题意膜你,输出即可!

主要思路

每层神经元只向下一层的神经元输出信息,只从上一层神经元接受信息。

所以,这是个 DAG。

非输入层的神经元开始时状态必然为 00

所以,读入时,先将最初状态为 00 的神经元的 type[] 设为 11,表示输入层。

因为数据范围较小(1n1001≤n≤100),直接在 bfs 中暴枚,找到 type[i]==1 的神经元。

将这些神经元压入队列。

在 bfs 中,算出各神经元的状态值:

  • 在拓展 ii 号神经元时,先算出 (j,i)EWjiCj\sum_{(j,i)\in E} {W_{ji}C_j}。(line 36)
  • 若要用此 ii 号神经元拓展其他点时,表明 \sum 运算已结束,减去阈值 UiU_i(line 29)。

在bfs,如果 flag(line 23)为真,表明这个神经元出度为 00,即为输出层(line 40)。

因为数据范围较小(1n1001≤n≤100),直接在数组中暴枚,找到 type[i]==2&&c[i]>0 的神经元,并输出。

难点在于,题目坑太多了!~~我太弱了,不知道大佬们用的拓扑排序,~~所以有什么不严谨的地方敬请指出。

坑 #1

我只是初中蒟蒻,公式看不懂啊!!!

Ci=(j,i)EWjiCjUiC_i=\sum_{(j,i)\in E} {W_{ji}C_j}-U_i

经过自学后,了解了,\sum 表示求和。i=1nai\sum_{i=1}^{n} a_i 等价于:

for(int i=1;i<=n;i++)
	sum+=a[i];//sum的结果

aAa\in A 表示 aa 这个元素包含在集合 AA 中。


所以 (j,i)EWjiCjUi\sum_{(j,i)\in E} {W_{ji}C_j} -U_i 就表示以下伪代码中 sum 的结果。

//对于i点
for(int tmp=head[i];tmp;tmp=e[i].nxt)//链式前向星,所有与i相连的神经元
{
    int j=e[i].end;
    sum+=e[tmp].len*c[j];
}
sum-=u[i];
//其中i,j,c[],u[]的意义与公式对应;e[tmp].len即w[j][i]

注意

  1. Ui-U_i 是减在后面!

  2. CiC_i 大于 00 时,该神经元处于兴奋状态,否则就处于平静状态。当神经元处于兴奋状态时,下一秒它会向其他神经元传送信号。所以在 Cj>0C_j >0 时,该神经元才会对 CiC_i 有贡献!

  3. 该公式对输入层不适用!

坑 #2

若输出层的神经元最后状态均为 00,则输出 NULL

题面有误:不是均为 00!是均小于等于 00

输出最后状态大于00输出层神经元状态,并且按照编号由小到大顺序输出。

已加粗。

坑 #3

当神经元处于兴奋状态时,下一秒它会向其他神经元传送信号,信号的强度为 CiC_i

其实“传送信号”就是参与公式运算!

坑 #4

W(j,i)W_{(j,i)}UiU_i 都有可能为负数或 00





本文作者:Yurchiu

本文链接:https://yz-hs.github.io/9492bebde047/

版权声明:本博客中所有原创文章除特别声明外,均允许规范转载,转载请注明出处。所有非原创文章,按照原作者要求转载。


By Yurchiu.
其他物件杂物收纳
Hitokoto

Yurchiu 说,除了她以外的人都很强!嘤嘤嘤~~
博客信息
文章数目
158
最近更新
08-21
本站字数
350.6k
文章目录