原题链接:https://www.luogu.org/problem/show?pid=1038#sub
翘了晚自习,在机房A掉了这道题。
其实这道题比较难看的是那个公式,有同学可能上来没能看明白(包括我也是
c[i] = w[i][j] * c[j] - u[i].
如果是邻接表存图,把w[i][j]换成edge[i].dis就好。
注意到每层神经元只向下一层的神经元输出信息,只从上一层神经元接受信息,看图也能看明白,这是一个很显然的DAG,那么可以考虑拓扑排序。
对于那个u数组,这个玩意用处不大,而且除了公式也不参与计算,输入后可以直接把那个数减掉。
使用拓扑排序的原因也很简单,如果你要算一个c[i],你需要先把之前那个c[j]算出来。题目要我们算终点(出度为0的点)的c值,那么就得先计算上一层,要计算上一层还得先计算上一层的上一层……最终,我们应该从第二层从上往下开始计算(第一层已经给出)。而这个计算的层次正好和拓扑排序方式相对应,所以考虑使用拓扑排序。
我喜欢用邻接表,读入的时候记录每个点的入度的出度,然后跑一次拓扑排序,排序的时候如果出现传递过程则更新c[i],直到排序完毕,我们就可以把最后面一层的c值算出来。
输出的时候判断,题目要输出c[i]>0的终点,照做就好了。输出的时候再加一个无输出标记,判断是不是输出NULL,就好了。
参考代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #define maxn 205 6 #define INF 2147483647 7 #define check cout << "ok" << endl; 8 using namespace std; 9 struct Edge{ 10 int from,to,dis; 11 }; 12 Edge edge[maxn]; 13 int head[maxn]; 14 int tot = 0; 15 int du_in[maxn]; 16 int du_out[maxn]; 17 int n,p; 18 int c[maxn],U[maxn]; 19 int from,to,dis; 20 bool flag = false; 21 22 void add_edge(int from,int to,int dis){ 23 edge[++tot].from = head[from]; 24 edge[tot].to = to; 25 edge[tot].dis = dis; 26 head[from] = tot; 27 } 28 29 void toposort(void){ 30 queue<int> q; 31 for (int i=1;i<=n;i++) 32 if (du_in[i] == 0) 33 q.push(i); 34 35 while (!q.empty()){ 36 int u = q.front(); 37 q.pop(); 38 if (c[u] <= 0){ 39 for (int i = head[u];i!=0;i = edge[i].from){ 40 int v = edge[i].to; 41 du_in[v]--; 42 if (du_in[v] = 0) 43 q.push(i); 44 } 45 continue; 46 } 47 for (int i=head[u];i!=0;i = edge[i].from){ 48 int v = edge[i].to; 49 c[v] += c[u] * edge[i].dis; 50 du_in[v]--; 51 if (du_in[v] == 0) 52 q.push(v); 53 } 54 55 } 56 57 58 } 59 60 61 int main(){ 62 cin >> n >> p; 63 for (int i=1;i<=n;i++) 64 cin >> c[i] >> U[i]; 65 for (int i=1;i<=n;i++) 66 if (c[i] == 0) 67 c[i] -=U[i]; 68 69 for (int i=1;i<=p;i++){ 70 cin >> from >> to >> dis; 71 add_edge(from,to,dis); 72 du_in[to]++; 73 du_out[from]++; 74 } 75 76 toposort(); 77 78 for(int i=1;i<=n;i++) 79 if(du_out[i]==0 && c[i]>0) { 80 cout << i << " " << c[i] << endl; 81 flag=true; 82 } 83 if(!flag) 84 cout << "NULL"; 85 return 0; 86 }