NOIP2003神经网络题解

本文详细解析了一种神经元网络计算模型,并通过拓扑排序算法解决该模型中的计算顺序问题。文章介绍了如何根据特定条件判断神经元是否兴奋,并进一步传播信号,同时讨论了输入层的特殊处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目戳这里

  • 这道题并不是很难,就是细(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,jE) 的值。

    • 举个栗子:

    QQ浏览器截屏未命名.png

    • 对于上面这个图,想要算出 F C 值,就要先算出 D E C 值,哇,这不就是赤裸裸的拓扑排序吗?qwq

    • 从上面那个图还可以看出,输入层是入度为 0 的点( ABC ),输出层是出度为 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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值