Strongly connected HDU - 4635

题面

传送门

题解

正难则反, 求多少条边不能建

首先完全连通图总边数 n * (n - 1)

减去给出的 m 条边

缩点之后, scc可以互连, 添加边, 使得最后留下一个 出度为1为, 入度为1 的连个 scc就可

即留下一个入度为1的scc, 其他scc建边完全联通, or 留下一个scc出度为1, 其他scc建边完全联通

int n, m, _, k;
vector<VI> h;
int c[N], scnt, st[N], top;
int dfn[N], df, low[N];
bool inst[N];

void tarjan(int x) {
    dfn[x] = low[x] = ++df, inst[st[++top] = x] = 1;
    for (auto &y : h[x]) {
        if (!dfn[y]) { tarjan(y); umin(low[x], low[y]); }
        else if (inst[y]) umin(low[x], dfn[y]);
    }
    if (low[x] == dfn[x]) {
        ++scnt; int y;
        do { inst[y = st[top--]] = 0; c[y] = scnt; } while (x != y);
    }
}

int main() {
    IOS; int cas = 0;
    for (cin >> _; _; --_) {
        cin >> n >> m; vector<VI>(n + 1).swap(h);
        cout << "Case " << ++cas << ": ";
        rep (i, 1, m) {
            int u, v; cin >> u >> v;
            h[u].pb(v);
        }
        memset(dfn, 0, sizeof dfn); df = scnt = 0;
        rep (i, 1, n) if (!dfn[i]) tarjan(i);
        if (scnt == 1) { cout << "-1\n"; continue; }
        VI cnt(scnt + 1); vector<bool> in(scnt + 1), out(scnt + 1);
        rep (i, 1, n) ++cnt[c[i]];
        rep (i, 1, n) for (auto &y : h[i]) if (c[i] != c[y]) in[c[y]] = out[c[i]] = 1;
        int ans = 1e9;
        rep (i, 1, scnt) if (!in[i] || !out[i]) umin(ans, cnt[i]);
        cout << (ll)n * (n - 1) - m - (ll)ans * (n - ans) << '\n';
    }
    return 0;
}
posted @ 2020-12-10 13:03  洛绫璃  阅读(46)  评论(0编辑  收藏  举报