1>神经网络
绿题
为什么用拓扑?
1)必备条件:DAG
2)本题的公式上,显示需要计算出能连接到本点的,全部的边值*点值
故而当我开始推这个点时,他的所有先驱点的状态全部都要求完
这只能是topo_sort
#include<cstdio> #include<cstdlib> #include<queue> #include<vector> using namespace std; int n,m; const int N=103; int c[N],in[N],sz[N]; struct node { int v,w; node(int vv,int ww) { v=vv,w=ww; } node(){} }; vector <node > g[N]; queue <int > q; void topo_sort() { while(!q.empty()) { int t=q.front();q.pop(); sz[t]=g[t].size() ; for(int i=0;i<sz[t];i++) { node v=g[t][i]; if(c[t]>0) c[v.v ]+=c[t]*v.w ; if(--in[v.v ]==0) q.push(v.v ); } } } int main() { scanf("%d%d",&n,&m); int x; for(int i=1;i<=n;i++) { scanf("%d%d",&c[i],&x); if(c[i]>0) q.push(i); else c[i]-=x; } int u,v,w; while(m--) { scanf("%d%d%d",&u,&v,&w); g[u].push_back(node(v,w)); in[v]++; } topo_sort(); bool fail=true; for(int i=1;i<=n;i++) if(!sz[i] && c[i]>0) { printf("%d %d\n",i,c[i]); fail=false; } if(fail) printf("NULL\n"); return 0; }
2>校园网络
>难点:
DAG中,如何加入最少的边,使图中所有边都在一个强连通分量中
>试着从in,out的方面分析问题,
加边:入度+1,出度+1
>推测 :
缩点 后的任意有向图
若要向其中添加一些边,使得仅存一个强连通分量,
添加边的数目min= max(入度为0的点 , 出度为0的点)
>证明:(luogu)
一个任意DAG,必定是由多个链形成的,必然有起点u和终点v
我们先建立u->v的边,嗯链少了一条,变成了点,
入度为0的点-1,出度为0的点-1
重复以上步骤,
直到最后所有的入度为0的点,出度为0的点,都消失了,
再看看图,就没有链了,都是环,或者说最后只剩下一个强连通分量
#include<cstdio> #include<cstdlib> #include<vector> #include<stack> #include<algorithm> using namespace std; int n,sum; const int N=10003; vector <int > g[N]; int fa[N],sz[N],dfn[N],low[N],tt; stack <int> s; bool f[N]; void tarjan (int x) { dfn[x]=low[x]=++tt; f[x]=true,s.push(x); sz[x]=g[x].size() ; for(int i=0;i<sz[x];i++) { int v=g[x][i]; if(!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if(f[v]) low[x]=min(low[x],low[v]); } if(dfn[x]==low[x]) { ++sum; while(s.top()!=x) f[s.top()]=false,fa[s.top()]=sum,s.pop(); f[x]=false,fa[x]=sum,s.pop() ; } } int in[N],out[N];//存sum节点的入度 int main() { scanf("%d",&n); int x; for(int i=1;i<=n;i++) while(~scanf("%d",&x) && x) g[i].push_back(x); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) { int fu=fa[i],fv; for(int j=0;j<sz[i];j++) { int v=g[i][j]; fv=fa[v]; if(fu!=fv) in[fv]++,out[fu]++; } } int ans1=0,ans2=0; for(int i=1;i<=sum;i++) { if(!in[i]) ans1++; if(!out[i]) ans2++; } printf("%d\n%d",ans1,max(ans1,ans2)); return 0; }
3>旅行计划