1038神经网络
这道题也可以用队列来做,但比较麻烦。。。。没办法,蒟蒻一枚。
首先,将起点(ci==1的点)放入队列之中。当head< tail时,
++head,将队首的点(team【head】)展开去找他的儿子节点。
如果儿子节点没放入队列则放入。l代表本层最后一个点在team【】中的序号,l2用于记录修改前的l,便于输出。当head==l时,则这一层的节点扫描毕。此时l+1到tail间的节点即是下一层的节点。对下一层的节点施行减ui【】操作,如果减完后的ci【】大于0,则这个节点处于兴奋状态,可以向下传递。若不能,则用ex【】(因为exst【】已经用来记录别的了。。。)打个标记阻止继续下传。循环完成后,l2+1到l(也就是tail)之间的便是解(注意只用输出大于0的,所以输出时加一个判定),至于co【】,只是为了按顺序输出用的。
解释写得够详细得了吧。。。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string>
#include<queue>
using namespace std;
int n,p,ta,ci[1000001],ui[1000001];
int head,l2,tail,team[1000001],exist[100010];
int ex[1000001],co[1000001],lx;
struct ac
{
int t,s,next,head,w;
}e[100001*4];
void build(int x,int y,int z)
{
e[++ta].t=y;
e[ta].w=z;
e[ta].s=x;
e[ta].next=e[x].head;
e[x].head=ta;
}//建图。
bool cmp(int a,int b)
{
return a<b;
}
int main()
{
cin>>n>>p;
for(int i=1;i<=n;++i)
{
cin>>ci[i]>>ui[i];
}
for(int i=1;i<=p;++i)
{
int a,b,c;
cin>>a>>b>>c;
build(a,b,c);
}
for(int i=1;i<=n;++i)
{
if(ci[i]!=0)
{
team[++tail]=i;
}
}//起点入队。 int l=tail;//此时l为第一层最后一个节点在team【】中的序号。
while(head<tail)
{
if(head==l)//当某一层循环完毕时,执行减ui【】操作。
{
for(int i=l+1;i<=tail;++i)
{
ci[team[i]]=ci[team[i]]-ui[team[i]];
if(ci[team[i]]<=0)//如果细胞不兴奋则标记。
{
ex[team[i]]=1;
}
}
l2=l;
l=tail;//更新l,l2.
}
head++; int u=team[head];
if(ex[u]!=1)//如果节点兴奋,则修改他的子节点。
{
for(int i=e[u].head;i;i=e[i].next)
{
int go=e[i].t;
ci[go]+=ci[e[i].s]*e[i].w;
if(exist[go]!=1)
{ //如果子节点未入队则入队。
exist[go]=1;
team[++tail]=go;
}
}
}
}
for(int i=l2+1;i<=tail;++i)
{
co[++lx]=team[i];
}
sort(co+1,co+1+lx,cmp);//从下到大输出。
if((ci[co[lx]]==0&&ci[co[1]]==0)||tail<n)
{
cout<<"NULL";//如果首尾都是0(因为sort过了,所以如果首尾都是0则全是0)或未遍历到输出层,则输出NULL。
}
else
{
for(int i=1;i<=lx;++i)
{
if(ci[co[i]]>0)
cout<<co[i]<<" "<<ci[co[i]]<<'\n';
}
}
return 0;
}