給定有向圖,求最多能加多少條邊使圖仍不是強連通圖。若原圖已強連通輸出 -1。n, m ≤ 1e5。
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int MAXN = 100005;
struct Edge { int to, next; } edges[MAXN * 2];
int head[MAXN], ecnt;
int dfn[MAXN], low[MAXN], stk[MAXN], top, idx, sccCnt;
int bel[MAXN], sz[MAXN];
int inDeg[MAXN], outDeg[MAXN];
void addEdge(int u, int v) {
edges[ecnt] = {v, head[u]};
head[u] = ecnt++;
}
void tarjan(int u) {
dfn[u] = low[u] = ++idx;
stk[++top] = u;
for (int e = head[u]; ~e; e = edges[e].next) {
int v = edges[e].to;
if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); }
else if (!bel[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
++sccCnt;
int v;
do { v = stk[top--]; bel[v] = sccCnt; sz[sccCnt]++; } while (v != u);
}
}
int main() {
int T; scanf("%d", &T);
for (int tc = 1; tc <= T; tc++) {
int n, m; scanf("%d%d", &n, &m);
ecnt = 0; memset(head, -1, sizeof(head));
for (int i = 0; i < m; i++) {
int u, v; scanf("%d%d", &u, &v);
addEdge(u, v);
}
memset(dfn, 0, sizeof(dfn));
memset(bel, 0, sizeof(bel));
memset(sz, 0, sizeof(sz));
idx = top = sccCnt = 0;
for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i);
if (sccCnt == 1) {
printf("Case %d: -1\n", tc);
continue;
}
memset(inDeg, 0, sizeof(inDeg));
memset(outDeg, 0, sizeof(outDeg));
for (int u = 1; u <= n; u++) {
for (int e = head[u]; ~e; e = edges[e].next) {
int v = edges[e].to;
if (bel[u] != bel[v]) {
outDeg[bel[u]]++;
inDeg[bel[v]]++;
}
}
}
LL total = 1LL * n * (n - 1) - m;
LL ban = 1LL << 60;
for (int i = 1; i <= sccCnt; i++) {
if (inDeg[i] == 0 || outDeg[i] == 0) {
ban = min(ban, 1LL * sz[i] * (n - sz[i]));
}
}
printf("Case %d: %lld\n", tc, total - ban);
}
return 0;
}
在 DAG 中,若選一個入度為 0 的分量 S,則無邊能進入 S。若我們添加所有除 `S → V\S` 以外的邊,圖仍不強連通(因 S 無法被到達)。這樣少加了 `sz[S]*(n-sz[S])` 條邊。同理出度為 0 的分量。為了最大化可加邊數,選擇使此乘積最小的分量。