题目戳这里
这道题并不是很难,就是细(keng)节(dian)有点多
如果一个神经元的 C[i]<=0 ,那他就不会exciting,不会继续传递。
C[i] 有可能是负数,所以输出的时候要判断 C[i]>0 而不是 C[i]!=0 。
U[i] 其实没必要存储下来,输入层的 U[i] 其实没什么用。具体看下面的分析。
分析题目中的公式
- 由 C[i]=∑(j,i)∈EW(j,i)∗C[j]−U[i] 移项可得
- C[i]+U[i]=∑(j,i)∈EW(j,i)∗C[j]
U[i] 是要输入进去的,可以视为一个常数 k
也就是说
∑ 算出来的是 C[i]+k 的值想得到 C[i] 就迟早要减去那个常数 k
所以我们可以在输入的时候就减去这个常数不就行了吗,何必要在后面减去呢?QAQ
输入层的
U 是没用的, U 只在公式里有用,输入层的C[i] 又不用计算,所以 U 没用。
为什么要用拓扑排序
再看上面的公式:
C[i]+U[i]=∑(j,i)∈EW(j,i)∗C[j] 发现要想求出 C[i] 就要求出所有 C[j](i,j∈E) 的值。
举个栗子:
对于上面这个图,想要算出 F 的
C 值,就要先算出 D 和E 的 C 值,哇,这不就是赤裸裸的拓扑排序吗?qwq从上面那个图还可以看出,输入层是入度为
0 的点( A、B、C ),输出层是出度为 0 的点(F ),如果你用的是邻接表存图你可以只记录入度不记录出度,因为一个点 u 出度为0 相当于 head[u]==0 ,所以输出的时候判断每个点的 head 和 C 就好了。
代码最好不要抄我的呀,我这个拓扑排序是用栈实现的(鬼知道我怎么YY出来的),貌似别人都是用的队列?
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 110
struct Edge {
int u,v,w,next;
Edge(int u=0,int v=0,int w=0,int next=0):
u(u),v(v),w(w),next(next) {}
}edge[20010];
int head[maxn],cnt;
int C[maxn];
int st[maxn],top;
int indeg[maxn];//入度;
inline int input() {
int x=0,a=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-') a=-1;
for(;c>='0'&&c<='9';c=getchar())
x=x*10+c-'0';
return x*a;
}
inline void addedge(int u,int v,int w) {
edge[++cnt]=Edge(u,v,w,head[u]);
head[u]=cnt;
return;
}
void topo() {
while(top!=0) {
int u=st[top--];
if(C[u]<=0) {
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].v;
indeg[v]--;
if(indeg[v]==0) st[++top]=v;
}
continue;
}
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].v;
C[v]+=C[u]*edge[i].w;
indeg[v]--;
if(indeg[v]==0) st[++top]=v;
}
}
return;
}
int main() {
int n=input(),p=input();
for(int i=1,U;i<=n;i++) {
C[i]=input();
U=input();
if(C[i]!=0) st[++top]=i;
else C[i]-=U;
}
for(int i=1;i<=p;i++) {
int u=input(),v=input(),w=input();
addedge(u,v,w);
indeg[v]++;
}
topo();
bool flag=false;
for(int i=1;i<=n;i++)
if(!head[i]&&C[i]>0) {
printf("%d %d\n",i,C[i]);
flag=true;
}
if(flag==false) printf("NULL");
return 0;
}
第一次写这么详细的题解。exciting。