CCF 201509-4 高速公路_Tarjan算法

CCF 201509-4 高速公路 传送门

这道题基本算是裸的Tarjan算法了, 只要求出每个强连通分量, 然后根据这些分量的元素数计算便利城市对即可, 数据也没有优化的坑. 会Tarjan算法的人大概会在考场上大呼简单, 但不会的人恐怕只有0分了, 说明CCF认证还是需要一定量的算法知识的.

第一稿只得了80分. 找了很多博客对比, 期间发现他们很多人, 一个简单的Tarjan算法写的那么复杂, 又乱又长, 无用的操作太多. 最后发现这个20分的错误是我算法的错误(题目还是裸的Tarjan算法). 在找到强连通分量时没有及时地标记出栈(in_stack[stack[top]] = false;). 所以我此前的算法根本是错的, 能得80分也是运气.

100分代码

#include <iostream>
#include <vector>
using namespace std;

const int max_n = 10005;
vector<int> G[max_n];
int dfn[max_n], low[max_n], ans = 0;
int n, m, stack[max_n], top = 0, index = 0;
bool in_stack[max_n];

void tarjan(int u)
{
    dfn[u] = low[u] = ++index;
    stack[++top] = u;
    in_stack[u] = true;
    for (int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if (!dfn[v]) { // 更新新的点.
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if (in_stack[v]) {
            low[u] = min(low[u], low[v]);
        } // 还剩下一种不在栈中但是已经访问过的情况,是其他连通分量的
    }
    if (dfn[u] == low[u]) {
        int cnt = 0;
        do {
            ++cnt;
            in_stack[stack[top]] = false; // 我靠, 漏写了这一条.
        } while (stack[--top + 1] != u);
        ans += (cnt - 1)*cnt / 2;
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 0, u, v; i < m; ++i) {
        cin >> u >> v;
        G[u].push_back(v);
    }
    for (int i = 1; i <= n; ++i) {
        if (!dfn[i]) tarjan(i);
    }
    cout << ans;
}

猜你喜欢

转载自blog.csdn.net/wjh2622075127/article/details/81570129