拓扑排序

首先就是例题,神经网络。

这道题有很多的做法,其实就是图的遍历,我最开始使用的bfs进行的遍历

然后第二遍做用的拓扑排序,排序后就可以满足在每个层开始时前面的层一定都已经遍历完了。这也就是拓扑排序的作用;

拓扑排序有两种写法,一种是记录出入度,用队列进行模拟,每次遍历完一条边之后将这条边的终点的入度减1,当有点的入度为0时,说明这个点之前的点都被遍历完了,那么将这个点加入队列继续遍历就好,如果入度出现了负数那一定就是出现了环。证明很简单,画个环就可以了,还有一种写法就是dfs,这里参照了刘汝佳书上的做法,思路明确,用栈记录,这里注意的是一定要dfs完了以后再将这个点加进去。用一个c数组储存当前的状态,0为未访问,-1为正在访问,1为已访问,如果在dfs过程中遇到了-1的点,那么说明出现了环,return false就行,至于为什么是dfs结束以后再加入点,很简单,dfs子节点结束之后才说明这个点的出度已经结束了,那么将这个节点加入到当前拓扑序的首部即可,为什么不是尾部? 因为子节点dfs优先结束,所以就像是回溯一样一步一步往回推得,如果加到尾部就全反了。

其实感觉图上遍历都是这样的,用各种辅助数组记录信息完成一些算法的实施,本质上还是遍历,就像是强连通分量一样。复杂度都是O(n),证明也很简单,这里不在给出赘述。

toposort模板如下:

int c[maxn],topo[maxn],t;

bool dfs(int u)

{    

    c[u]=-1;

    for(int v=0;v<n;v++)if(G[u][v])

    {

        if(c[v]<0)return false;

        else if(!c[v]&&!dfs(v))return false;

    }

    c[u]=1;topo[t--]=u;

    return true;

}

初始化这里也不再给出,当然拓扑排序可以随着题目不同而灵活使用,下面给出toposort应用在神经网络这道题上的代码

同样做了一些小变化,不再死板的使用了-1 和1 记录状态

代码:

dfs

#include<iostream>
using namespace std;
struct line
{
    int to,w,next;
}edge[100005];
int n,tot,p,now;
int u[101],c[101],g[101],s[100001],ind[101],outd[101];
bool vis[101];
void add1(int a,int b,int c)
{
    edge[++tot].to=b;
    edge[tot].w=c;
    edge[tot].next=g[a];
    g[a]=tot;
}
void dfs(int u)
{
    vis[u]=true;
    int temp=g[u];
    while(temp)
    {
        if(!vis[edge[temp].to])dfs(edge[temp].to);
        temp=edge[temp].next;
    }
    s[now--]=u;
}
void toposort()
{
    now=n;
    for(int i=1;i<=n;i++)if(ind[i]==0&&vis[i]==false)dfs(i);
}
int main()
{
    cin>>n>>p;
    for(int i=1;i<=n;i++)
    {
        cin>>c[i]>>u[i];
        if(!c[i])c[i]-=u[i];
    }
    for(int i=1;i<=p;i++)
    {
        int x=0,y=0,z=0;
        cin>>x>>y>>z;
        add1(x,y,z);
        ind[y]++;
        outd[x]++;
    }
    toposort();
    for(int i=1;i<=n;i++)
    {
        if(c[s[i]]<=0)continue;
        int temp=g[s[i]];
        while(temp)
        {
            c[edge[temp].to]+=c[s[i]]*edge[temp].w;
            temp=edge[temp].next;
        }
    }
    int flag=0;
    for(int i=1;i<=n;i++)
    {
        if(outd[i]==0&&c[i]>0)
        {
            cout<<i<<" "<<c[i]<<endl;
            flag++;
        }
    }
    if(!flag)cout<<"NULL";
    return 0;

}

bfs

#include<iostream>
using namespace std;
struct line
{
    int to,w,next;
}edge[100005];
int n,tot,p;
int u[101],c[101],g[101],q[100001],ind[101],outd[101];
void add1(int a,int b,int c)
{
    edge[++tot].to=b;
    edge[tot].w=c;
    edge[tot].next=g[a];
    g[a]=tot;
}
void toposort()
{
    int h=0,t=0;
    for(int i=1;i<=n;i++)
    {
        if(ind[i]==0)
        {
            t++;
            q[t]=i;
        }
    }
    while(h!=t)
    {
        h++;
        int temp=g[q[h]];
        while(temp)
        {
            ind[edge[temp].to]--;
            if(ind[edge[temp].to]==0)
            {
                t++;
                q[t]=edge[temp].to;
            }
            temp=edge[temp].next;
        }
    }
}
int main()
{
    cin>>n>>p;
    for(int i=1;i<=n;i++)
    {
        cin>>c[i]>>u[i];
        if(!c[i])c[i]-=u[i];
    }
    for(int i=1;i<=p;i++)
    {
        int x=0,y=0,z=0;
        cin>>x>>y>>z;
        add1(x,y,z);
        ind[y]++;
        outd[x]++;
    }
    toposort();
    for(int i=1;i<=n;i++)
    {
        if(c[q[i]]<=0)continue;
        int temp=g[q[i]];
        while(temp)
        {
            c[edge[temp].to]+=c[q[i]]*edge[temp].w;
            temp=edge[temp].next;
        }
    }
    int flag=0;
    for(int i=1;i<=n;i++)
    {
        if(outd[i]==0&&c[i]>0)
        {
            cout<<i<<" "<<c[i]<<endl;
            flag++;
        }
    }
    if(!flag)cout<<"NULL";
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值