有N个城市,它们之间存在一些单向路径,若可以从城市i到城市j,则一定无法从城市j到达城市i,只出不入的城市称为源点城市,只入不出的城市称为终点城市。已知到达某个城市就可以获得或者失去一定的钱财。现在狗先生从某个源点出发,到达某个终点停止,他想拥有尽量多的钱财。要求给出最多的钱财是多少。
题目给定的是一个有向无环图。最多的钱财可以转换成最短路径问题,每条边的权重其实就是到达该边的终点得到或失去的钱财。有向无环图的单源最短路径可以采用先拓扑排序再按照顺序遍历各个点的边进行松弛的方法进行。由于没有环,因此肯定存在最短路径。把最短路径转换为最长路径就可以解决这个问题了。
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 100005; const int E = 1200005; const int MAX = 99999999; struct Edge { int pnt; int dis; int next; }; Edge edge[E]; int cur; int neigh[N]; int val[N]; int indegree[N], outdegree[N]; int maxdis[N]; int topoqueue[N]; int n, e; void addedge(int beg, int end, int dis) { ++outdegree[beg]; ++indegree[end]; edge[cur].pnt = end; edge[cur].dis = dis; edge[cur].next = neigh[beg]; neigh[beg] = cur; ++cur; } void toposort() { int front, rear, node, te, pnt; front = rear = 0; topoqueue[rear++] = 0; while (front != rear) { node = topoqueue[front++]; te = neigh[node]; while (te != -1) { pnt = edge[te].pnt; --indegree[pnt]; if (indegree[pnt] == 0) topoqueue[rear++] = pnt; te = edge[te].next; } } } void relax(int u, int v, int dis) { if (maxdis[u] + dis > maxdis[v]) maxdis[v] = maxdis[u] + dis; } void dag() { for (int i = 0; i <= n + 1; ++i) maxdis[i] = -MAX; int topo_pt = 0; int te, pnt, node; maxdis[0] = 0; while (topo_pt <= n + 1) { node = topoqueue[topo_pt++]; te = neigh[node]; while (te != -1) { pnt = edge[te].pnt; relax(node, pnt, edge[te].dis); te = edge[te].next; } } } int main() { int beg, end; while (scanf("%d%d", &n, &e) != EOF) { cur = 0; for (int i = 0; i <= n + 1; ++i) { neigh[i] = -1; indegree[i] = outdegree[i] = 0; } for (int i = 1; i <= n; ++i) scanf("%d", &val[i]); for (int i = 0; i < e; ++i) { scanf("%d%d", &beg, &end); addedge(beg, end, val[end]); } for (int i = 1; i <= n; ++i) { if (indegree[i] == 0) addedge(0, i, val[i]); if (outdegree[i] == 0) addedge(i, n + 1, 0); } toposort(); dag(); printf("%d\n", maxdis[n + 1]); } return 0; }