洛谷 P1038 [NOIP2003 提高组] 神经网络

原题连接

https://www.luogu.com.cn/problem/P1038


主要思路

该题是一个拓扑搜索的过程,通过记录入度,从入度为零的点逐步搜索全图即可。
有几个细节需要注意:
1、并不是所有的结点都要减掉阈值,输入层的结点不需要减掉。虽然测试样例输入层的结点阈值都为0,但题目并没有明确指出。
2、当一个结点的状态c不大于0时,仍然要拓扑,否则后面的几个结点的入度可能无法减到0,导致无法拓扑全图。
3、特判NULL的情况


代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 100 + 10;
int n, p;
struct node {
    
    
	int c; // 状态
	int u; // 阈值
	int in = 0, out = 0; // 该点的入度和出度
}a[maxn];

vector<pair<int ,int> > r[maxn * maxn]; // 路径,1、目的结点 2、权值
queue<int> rd, cd; // 队列存入度为0和出度为0的结点

int main() {
    
    
	cin >> n >> p;
	for (int i = 1; i <= n; i++) {
    
    
		cin >> a[i].c >> a[i].u;
		a[i].c -= a[i].u; // 所有的点事先减掉阈值,注意:输入层的还要加回来
	}
	for (int i = 1; i <= p; i++) {
    
    
		int u, v, w;
		cin >> u >> v >> w;
		a[u].out++;
		a[v].in++;
		r[u].push_back({
    
     v, w });
	}
	for (int i = 1; i <= n; i++) {
    
    
		if (a[i].in == 0)
			rd.push(i), a[i].c += a[i].u; // 输入层入队列,加回阈值
		if (a[i].out == 0)
			cd.push(i);
	}
	while (!rd.empty()) {
    
    
		int x = rd.front();
		rd.pop();
		for (auto i : r[x]) {
    
     // 遍历以x为起始节点的所有的路径
			if(a[x].c > 0) // 只有当状态大于0,才为下一个结点加,但是无论是否大于零,都要拓扑一遍,保证所有的入度都会减掉
				a[i.first].c += i.second * a[x].c;
			if (--a[i.first].in == 0) rd.push(i.first); // 入度为零,入队列
		}
	}
	bool flag = false;
	while (!cd.empty()) {
    
    
		if (a[cd.front()].c > 0)
			cout << cd.front() << " " << a[cd.front()].c << endl, flag = true;
		cd.pop();
	}
	if (!flag) cout << "NULL";
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Salvator_/article/details/123056485