1
/**/
/*
2
=========程序信息========
3
对应题目:noip2003提高组_神经网络
4
使用语言:c++
5
使用编译器:dev c++
6
使用算法:模拟
7
算法运行时间:O(n^2 * layer) 其中layer为层数,最大为n。[明显这个神经网络是一个稀疏图,如果改用链表存储方法存储图的边的话将大大减小运行时间。]
8
作者:贵州大学05级 刘永辉
9
昵称:SDJL
10
编写时间:2008年8月
11
联系QQ:44561907
12
E-Mail:44561907@qq.com
13
获得更多文章请访问我的博客:www.cnblogs.com/sdjl
14
如果发现BUG或有写得不好的地方请发邮件告诉我:)
15
=========题目解析========
16
题目补充点一:题目中出现的那个公式中有一个向又开口的符号(下面用“E”表示),那个是求和符号,在此题中表示第i个神经原的C值等于所有 指向第i个神经元的边的W值乘于发出信号的神经元的C值 的和,最后在减去第i个神经元的U值,注意U在整个公式中仅减一次(刚接触E符号的人会把Ewc-u理解为E(wc - u),事实上应该是E(wc) - u)。
17
18
这是一个模拟题,因为信号是一层一层地传递的,所以我们可以仅关心当前的发送层有哪些神经元,以及接收信号层有哪些神经元.并且每一个神经元仅有一次机会进入发送层,同 样也仅有一次机会进入接收层,在一个神经元进入接收层后下一秒它必定将进入发送层(注意:进入发送层不一定就会发送信号,当神经元处于平静状态时它是不会发送信号的,但它依然属于发送层!)。
19
在读取数据后,依据题目可以根据c[i]是否大于0来判断初始时哪些神经元属于发送层。
20
我们用senderLayer[i]==true表示第i个元素属于发送层的神经元,用incepterLayer[i]==true表示第i个元素属于接收层的神经元,当接收层中的神经元数大于0时,表示神经信号传递的过程还没有结束,此时我们要利用题目给出的公式计算接受层中每一个神经元的状态值,直到接收层中的神经元数为0时信号传递过程结束,程序结束。
21
*/
22
23
24
//
=================代码如下================
25
#include
<
cstdlib
>
26
#include
<
iostream
>
27
#include
<
fstream
>
28
29
using
namespace
std;
30
31
const
int
maxn
=
200
;
//
最大神经元数目
32
int
n;
//
神经元数目
33
int
w[maxn][maxn];
//
w[i][j]为第i个神经元与第j个神经元之间边的权值
34
int
c[maxn];
//
神经元的状态,当c[i]>0时第i个神经元处于兴奋状态,下一秒它会向其他神经元传送信号,信号的强度为Ci
35
int
u[maxn];
//
u[i]是阈值,可视为神经元的一个内在参数,在公式中有用
36
bool
senderLayer[maxn];
//
senderLayer[i]==true表示第i个元素属于发送层的神经元
37
bool
incepterLayer[maxn];
//
incepterLayer[i]==true表示第i个元素属于接收层的神经元
38
39
//
初始化数据
40
void
init()
41
{
42
//初始化w为0============================
43
for(int i=0; i<maxn; i++)
44
for(int j=0; j<maxn; j++)
45
w[i][j] = 0;
46
47
//初始化c、u为零,清空发送层与接收层中的神经元==============================
48
for(int i=0; i<maxn; i++)
49
{
50
c[i] = 0;
51
u[i] = 0;
52
senderLayer[i] = false;
53
incepterLayer[i] = false;
54
}
55
56
//读取数据c、u,并初始化发送层神经元=====================================
57
ifstream inputFile("network.in");//输入文件名为network.in
58
int p;//边数,与题目对应
59
//[编程风格提示:p的定义不要和n写在一起,n是全局都回使用到的一个值,而p仅在读取边数时有用,变量的定义应该接近第一次使用它的地方]
60
inputFile>>n>>p;
61
for(int i=0; i<n; i++)
62
{
63
inputFile>>c[i]>>u[i];
64
65
/**//*
66
如果神经元处于兴奋状态,则把神经元加入接收层.注意:按理来说我们此时因该把第i个神经元加入发送层,而不是接收层,
67
但是这并不是笔误,之所以是incepterLayer[i] = true而不是senderLayer[i] = true是有原因的,你可以暂时不用管,
68
看到下面的代码时我会解释,我们先把这里假设为谜团一!
69
*/
70
if(c[i]>0)
71
incepterLayer[i] = true;
72
}
73
74
//读取边权值===============================================
75
int i,j;
76
for(int k=0; k<p; k++)
77
{
78
inputFile>>i>>j;
79
inputFile>>w[i-1][j-1];//题目是从1开始编号,而我们编程从0开始编号,所以减去1
80
}
81
82
inputFile.close();
83
84
}
85
86
/**/
/*
87
获取下一秒发送层与接收层中的神经元,并且返回下一秒接收层中神经元的个数,这个返回值用于判断模拟过程是否结束
88
[编程风格提示1:这里GetIncepterLayer方法从名字上来看它仅计算出了接收层中的神经元,而实际上它同时计算了发送层的神经元,因此GetSenderLayerAndIncepterLayer也许会更加准确,但是这个名字太长了!]
89
[编程风格提示2:这里GetIncepterLayer不但获得了两个层中的神经元,还同时计算并返回了接收层中神经元数,这是一种不好的设计,按道理来说,我们因该遵守一个方法一个职责的原则,而这里的GetIncepterLayer具有了两个原则。]
90
*/
91
int
GetIncepterLayer()
92
{
93
//下一秒的发送层等于上一秒的接收层,而下一秒的接收层暂时为空=======================
94
for(int i=0; i<n; i++)
95
{
96
senderLayer[i] = incepterLayer[i];
97
incepterLayer[i] = false;
98
}
99
100
101
int incepterLayerCount = 0; //下一秒的接收层中神经元个数
102
//计算下一秒中神经元
103
for(int i=0; i<n; i++)
104
{
105
if(senderLayer[i] == true)
106
{
107
for(int j=0; j<n; j++)
108
if(w[i][j]>0)
109
{
110
incepterLayer[j] = true;
111
incepterLayerCount++;
112
}
113
}
114
}
115
116
return incepterLayerCount;
117
}
118
119
//
运行信号传递模拟过程
120
void
run()
121
{
122
//如果下一秒钟接收层中神经元不为空时继续传递信号
123
//注意:当第一次调用GetIncepterLayer时发生了什么?发送层初始如何?结束时如何?接收层初始如何?结束时又如何?想一想就知道谜团一了!
124
while(GetIncepterLayer() > 0)
125
{
126
//j是发送层中的神经元,i是接收层中的神经元,与题目对应
127
for(int j=0; j<n; j++)
128
for(int i=0; i<n; i++)
129
//如果j在发送层中,i在接收层中,且j处于兴奋状态
130
if( (senderLayer[j] == true) && (incepterLayer[i] == true) && (c[j]>0) )
131
{
132
c[i] += w[j][i] * c[j];
133
}
134
135
for(int i=0; i<n; i++)
136
if(incepterLayer[i] == true)
137
c[i] -= u[i];
138
}
139
}
140
141
//
显示数据(输出到屏幕)
142
void
show()
143
{
144
bool nullAnswer = true;
145
for(int i=0; i<n; i++)
146
if((senderLayer[i] == true) && (c[i] > 0))
147
{
148
cout<<i+1<<' '<<c[i]<<endl;//输出编号时记得加1,这是因为编程从0开始编号
149
nullAnswer = false;
150
}
151
152
if(nullAnswer == true )
153
cout<<"NULL";
154
}
155
156
//
主函数调用
157
int
main(
int
argc,
char
*
argv[])
158
{
159
160
init();//初始化数据,从文件network.in中读入全局变量数据n、w、c、u,以及计算出初始发送层
161
run();//进行模拟过程
162
show();//显示数据(输出到屏幕)
163
system("PAUSE");
164
return EXIT_SUCCESS;
165
}
166


2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41



42

43

44

45

46

47

48

49



50

51

52

53

54

55

56

57

58

59

60

61

62



63

64

65


66

67

68

69

70

71

72

73

74

75

76

77



78

79

80

81

82

83

84

85

86


87

88

89

90

91

92



93

94

95



96

97

98

99

100

101

102

103

104



105

106



107

108

109



110

111

112

113

114

115

116

117

118

119

120

121



122

123

124

125



126

127

128

129

130

131



132

133

134

135

136

137

138

139

140

141

142

143



144

145

146

147



148

149

150

151

152

153

154

155

156

157

158



159

160

161

162

163

164

165

166
