为了更好地理解Tarjan算法,避免常见错误,以下是对一个典型问题的分析与解决方案。
初始代码(部分正确):
//缩点
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 1e6 + 5, MAXM = 1e4 + 5;
int n, m, a[MAXN], result, distance[MAXN], componentID[MAXN], predecessor[MAXN];
int edge[MAXN], nextEdge[MAXN], head[MAXN], weight[MAXN], indexCounter;
int discoveryTime[MAXN], lowLink[MAXN], sizeComponent[MAXN], stackNode[MAXN];
int timeCounter, topStack, sccCount;
bool visited[MAXN];
void addEdge(int from, int to) {
edge[indexCounter] = to, nextEdge[indexCounter] = head[from], head[from] = indexCounter++;
}
void tarjanAlgorithm(int node) {
lowLink[node] = discoveryTime[node] = ++timeCounter;
stackNode[++topStack] = node, visited[node] = true;
for (int i = head[node]; ~i; i = nextEdge[i]) {
int adjNode = edge[i];
if (!discoveryTime[adjNode]) tarjanAlgorithm(adjNode), lowLink[node] = min(lowLink[node], lowLink[adjNode]);
else if (visited[adjNode]) lowLink[node] = min(lowLink[node], discoveryTime[adjNode]);
}
if (lowLink[node] == discoveryTime[node]) {
int y;
++sccCount;
do {
y = stackNode[topStack--];
visited[y] = false, componentID[y] = sccCount;
if (node == y) break;
a[node] += a[y];
} while (y != node);
}
}
void topologicalSort() {
queue<int> q;
for (int i = 1; i <= n; i++) if (componentID[i] == i && !predecessor[i]) q.push(i), distance[i] = a[i];
while (!q.empty()) {
int current = q.front(); q.pop();
for (int i = head[current]; ~i; i = nextEdge[i]) {
int nextNode = edge[i];
predecessor[nextNode]--;
distance[nextNode] = max(distance[nextNode], distance[current] + a[nextNode]);
if (!predecessor[nextNode]) q.push(nextNode);
}
}
}
修正后的代码:
//使用Tarjan算法将图转换为DAG并计算最长路径
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, result, predecessor[MAXN], distance[MAXN], value[MAXN];
int edge[MAXN], nextEdge[MAXN], head[MAXN], index;
vector<int> graph[MAXN];
bool visited[MAXN];
int discovery[MAXN], lowLink[MAXN], stackNode[MAXN], componentID[MAXN];
int sccCount, timeCounter, topStack;
void addEdge(int u, int v) {
edge[index] = v, nextEdge[index] = head[u], head[u] = index++;
}
void tarjanAlgorithm(int u) {
lowLink[u] = discovery[u] = ++timeCounter;
stackNode[++topStack] = u, visited[u] = true;
for (int i = head[u]; ~i; i = nextEdge[i]) {
int v = edge[i];
if (!discovery[v]) tarjanAlgorithm(v), lowLink[u] = min(lowLink[u], lowLink[v]);
else if (visited[v]) lowLink[u] = min(lowLink[u], discovery[v]);
}
if (lowLink[u] == discovery[u]) {
int v;
++sccCount;
do {
v = stackNode[topStack--];
visited[v] = false, value[sccCount] += value[v], componentID[v] = sccCount;
} while (v != u);
}
}
void topologicalSort() {
queue<int> q;
for (int i = 1; i <= sccCount; i++) if (!predecessor[i]) q.push(i), distance[i] = value[i];
while (!q.empty()) {
int current = q.front(); q.pop();
for (int i = 0; i < graph[current].size(); i++) {
int nextNode = graph[current][i];
predecessor[nextNode]--;
distance[nextNode] = max(distance[nextNode], distance[current] + value[nextNode]);
if (!predecessor[nextNode]) q.push(nextNode);
}
}
}
int main() {
cin >> n >> m;
memset(head, -1, sizeof head);
for (int i = 1; i <= n; i++) cin >> value[i];
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
addEdge(x, y);
}
for (int i = 1; i <= n; i++) if (!discovery[i]) tarjanAlgorithm(i);
for (int i = 1; i <= n; i++)
for (int j = head[i]; ~j; j = nextEdge[j]) {
int k = edge[j];
int x = componentID[i], y = componentID[k];
if (x != y) graph[x].push_back(y), predecessor[y]++;
}
topologicalSort();
for (int i = 1; i <= n; i++) result = max(result, distance[i]);
cout << result << endl;
return 0;
}