HDU 4635 Strongly connected
强连通分量+缩点+公式推导
缩点之后,记录一下每个缩点的真实点有几个,计算一个每个点的入度与出度,然后找出入度或出度为0,并且真实点个数最少的那个缩点,其余的点都可以随便连边了,这个缩点只能单向的向外界连边。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int maxn = 100000 + 10; int Dfn[maxn], U[100000 + 10], V[100000 + 10], Belong[maxn]; int In[maxn], Out[maxn], flag[maxn]; int SUM[maxn]; struct Point { int id, dfn; } point[maxn]; vector<int>G[maxn]; vector<int>FG[maxn]; int N, Tot; int M, Block, in, out; void init() { for (int i = 0; i<maxn; i++) G[i].clear(); for (int i = 0; i<maxn; i++) FG[i].clear(); memset(Dfn, 0, sizeof Dfn); memset(In, 0, sizeof In); memset(Out, 0, sizeof Out); memset(flag, 0, sizeof flag); memset(SUM, 0, sizeof SUM); memset(Belong, 0, sizeof Belong); Tot = 0;//时间戳 Block = 0;//强连通分量的数目 in = 0;//统计入度为0的点的数目 out = 0;//统计出度为0的点的数目 } bool cmp(const Point&a, const Point&b) { return a.dfn>b.dfn; } void Dfs(int now) { flag[now] = 1; for (int i = 0; i<G[now].size(); i++) if (!flag[G[now][i]]) Dfs(G[now][i]); Tot++; Dfn[now] = Tot; } void dfs(int now) { Belong[now] = Block; for (int i = 0; i<FG[now].size(); i++) if (!Belong[FG[now][i]]) dfs(FG[now][i]); } int main() { int Case, cAse; scanf("%d", &cAse); for (Case = 1; Case <= cAse; Case++) { scanf("%d%d", &N, &M); init(); for (int i = 1; i <= M; i++) { scanf("%d%d", &U[i], &V[i]); G[U[i]].push_back(V[i]); FG[V[i]].push_back(U[i]); } for (int i = 1; i <= N; i++) if (!flag[i]) Dfs(i); for (int i = 0; i<N; i++) point[i].id = i + 1, point[i].dfn = Dfn[i + 1]; sort(point, point + N, cmp); for (int i = 0; i<N; i++) if (!Belong[point[i].id]) Block++, dfs(point[i].id); for (int i = 1; i <= M; i++) if (Belong[U[i]] != Belong[V[i]]) Out[Belong[U[i]]]++, In[Belong[V[i]]]++; for (int i = 1; i <= N; i++) SUM[Belong[i]]++; int St, MMA = 0x7FFFFFFF; for (int i = 1; i <= Block; i++) if ((!In[i] || !Out[i]) && (SUM[i]<MMA)) MMA = SUM[i], St = i; int MK = 0; int ML = 0; for (int i = 1; i <= M; i++) { if (Belong[U[i]] == St && Belong[V[i]] == St) ML++; if (Belong[U[i]] == St || Belong[V[i]] == St) continue; MK++; } int Pri = (N - SUM[St])*(N - SUM[St] - 1) - MK + (N - SUM[St])*SUM[St] - max(In[St], Out[St]) + (SUM[St])*(SUM[St] - 1) - ML; printf("Case %d: ", Case); if (Block == 1) printf("-1\n"); else printf("%d\n", Pri); } return 0; }