[CCF CSP]201509-4 高速公路

思路:先缩点,每个强连通分量对答案的贡献为sum*(sum-1)/2 ,其中sum为强连通分量大小

用tarjan算法求强连通分量(自己写了一个前向星版本的挂了,只有10分,tarjan算法的框架还是要背熟练!!!

#include<bits/stdc++.h>
using namespace std;
const int N = 10005;
vector<int> g[N];
stack<int> s;
int cnt,vis[N], dfn[N], low[N],ans;

void tarjan(int u)
{
    dfn[u] = low[u] = ++cnt;
    s.push(u);
    vis[u]=1;
    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 (vis[v])
            low[u] = min(low[u], dfn[v]);//编写时易错,是dfn而不是low
    }
    if (dfn[u] == low[u])
    {
        int sum=0;
        while (true)
        {
            int x = s.top();
            s.pop();
            sum++;
            vis[x]=0;
            if (x == u) break;
        }
        ans+=sum*(sum-1)/2;
    }
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int n, m;
    cin >> n >> m;
    int u, v;
    for (int i = 1; i <= m; i++)
    {
        cin >> u >> v;
        g[u].push_back(v);
    }
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(vis, 0, sizeof(vis));
    cnt = 0, ans = 0;
    for (int i = 1; i <= n; i++)
        if (!dfn[i]) tarjan(i);
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/Andrew-aq/p/12514285.html