首先就是例题,神经网络。
这道题有很多的做法,其实就是图的遍历,我最开始使用的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;
}