【原题】【数据结构】【noip 2003 T1】神经网络(图论)

问题

在兰兰的模型中,神经网络就是一张有向图,图中的节点称为神经元,而且两个神经
元之间至多有一条边相连,下图是一个神经元的例子:
::点击图片在新窗口中打开::
  神经元〔编号为1)
图中,X1—X3是信息输入渠道,Y1-Y2是信息输出渠道,C1表示神经元目前的状态,
Ui是阈值,可视为神经元的一个内在参数。
神经元按一定的顺序排列,构成整个神经网络。在兰兰的模型之中,神经网络中的神
经无分为几层;称为输入层、输出层,和若干个中间层。每层神经元只向下一层的神经元
输出信息,只从上一层神经元接受信息。下图是一个简单的三层神经网络的例子。
::点击图片在新窗口中打开::兰兰规定,Ci服从公式:(其中n是网络中所有神经元的数目)
::点击图片在新窗口中打开::
公式中的Wji(可能为负值)表示连接j号神经元和 i号神经元的边的权值。当 Ci大于0时,该神经元处于兴奋状态,否则就处于平静状态。当神经元处于兴奋状态时,下一秒
它会向其他神经元传送信号,信号的强度为Ci。
如此.在输入层神经元被激发之后,整个网络系统就在信息传输的推动下进行运作。
现在,给定一个神经网络,及当前输入层神经元的状态(Ci),要求你的程序运算出最后网络输出层的状态。

输入格式 Input Format

输入文件第一行是两个整数n(1≤n≤200)和p。接下来n行,每行两个整数,第i+1行是神经元i最初状态和其阈值(Ui),非输入层的神经元开始时状态必然为0。再下面P行,每行由两个整数i,j及一个整数Wij,表示连接神经元i、j的边权值为Wij。

输出格式 Output Format

输出文件包含若干行,每行有两个整数,分别对应一个神经元的编号,及其最后的状
态,两个整数间以空格分隔。仅输出最后状态非零的输出层神经元状态,并且按照编号由
小到大顺序输出!
若输出层的神经元最后状态均为 0,则输出 NULL。

分析

直接模拟就好了,也涉及不到什么特别高深的算法。对每个点计算其兴奋值。一开始想到了spfa,不行。因为它遍历的顺序存在问题,也就是说存在输入还没有输入完,就开始输出。这样显然是不对的。

我们想到了,要按照一定的顺序来遍历这些点,如何划分阶段呢?拓扑排序!每次找入度为零的点,然后删除它的初度,将它的值赋给与它临接的点。知道搜到最后一层,输出即可。

特别注意,一个点的c值如果不满足大于零,它不会对下个点传导兴奋。注意题目要求,一开始只有传入神经的c值不为零,所以我们完全可以将u的值加入c中,如果读入c=0则c付成-u,如果c<>0,则c付成c。也就是说传入神经不满足公式,这样就很好的解决了只有传入神经的数据。

以上这些只有在仔细分析题意之后才能得出。

反思

noip数据结构一般会停留在基础算法,不要只想着最短路,top排序,生成树等算法也要想一想。

仔细读题,多分析,只会算法的话不代表能够拿到分数,一定要注意隐含条件,注意题目要求,数据特点,可能错误等,不要急于代码!

code

program liukeke;
var
  c:array[0..205] of longint;
  into:array[0..205] of longint;
  q:array[0..100000] of longint;
  map,a:array[0..205,0..205] of longint;
  i,n,p,cc,u,x,y,z,l,r,now:longint;
  flag:boolean;

begin
  readln(n,p);
  for i:=1 to n do
  begin
    readln(cc,u);
	if cc=0 then
	  c[i]:=-u
	else
	begin
	  c[i]:=cc;
	  inc(r);
	  q[r]:=i;
	end;
  end;
  for i:=1 to p do
  begin
    readln(x,y,z);
	map[x,y]:=z;
	inc(a[x,0]);
	a[x,a[x,0]]:=y;
	inc(into[y]);
  end;
  l:=0;
  while l<r do
  begin
    inc(l);
	now:=q[l];
	for i:=1 to a[now,0] do
	begin
	  inc(c[a[now,i]],map[now,a[now,i]]*c[now]);
	  dec(into[a[now,i]]);
	  if (into[a[now,i]]=0)and(c[a[now,i]]>0) then
	  begin
	    inc(r);
		q[r]:=a[now,i];
	  end;
	end;
  end;
  flag:=true;
  for i:=1 to n do
    if (a[i,0]=0) and (c[i]>0) then
	begin
	  flag:=false;
	  writeln(i,' ',c[i]);
	end;
  if flag then writeln('NULL');
end.

posted @ 2010-11-16 17:20  liukee  阅读(1015)  评论(0编辑  收藏  举报