UVA-11324 The Largest Clique 【有向图强连通+缩点+DP】
题目链接:https://vjudge.net/problem/UVA-11324
题目大意:给定一张有向图G,求一个结点数最大的结点集,集合中每两个点都至少有一条路径相连(方向任意)。
题解:
易知如果一个点被选择,则它所在强连通分量中的其他点也一定要选,如果不选,则其他点也不可选,因此先求出强连通分量,利用缩点创建出另一张有向图G2,每个结点的权值就是该强连通分量的结点数,再DP求解。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define M(a, b) memset(a, b, sizeof(a)) 4 #define INF 0x3f3f3f3f 5 const int N = 1000 + 5; 6 int pre[N], sccno[N], val[N], dfs_clock, scc_cnt; 7 bool G2[N][N]; 8 vector<int> G[N]; 9 stack<int> S; 10 11 int dfs(int u) { 12 int lowu = pre[u] = ++dfs_clock; 13 S.push(u); 14 for (int i = 0; i < G[u].size(); ++i) { 15 int v = G[u][i]; 16 if (!pre[v]) { 17 int lowv = dfs(v); 18 lowu = min(lowu, lowv); 19 } 20 else if (!sccno[v]) lowu = min(lowu, pre[v]); 21 } 22 if (lowu == pre[u]) { 23 ++scc_cnt; 24 while (true) { 25 int x = S.top(); S.pop(); 26 sccno[x] = scc_cnt; 27 ++val[scc_cnt]; 28 if (x == u) break; 29 } 30 } 31 return lowu; 32 } 33 34 void find_scc(int n) { 35 M(pre, 0); M(sccno, 0); M(val, 0); 36 dfs_clock = scc_cnt = 0; 37 for (int i = 0; i < n; ++i) 38 if (!pre[i]) dfs(i); 39 } 40 41 int dp(int u) { 42 int ans = 0; 43 for (int i = 1; i <= scc_cnt; ++i) 44 if (G2[u][i]) ans = max(ans, dp(i)+val[i]); 45 return ans; 46 } 47 48 int main() { 49 int T, n, m; 50 scanf("%d", &T); 51 while (T--) { 52 scanf("%d%d", &n, &m); 53 for (int i = 0; i < n; ++i) G[i].clear(); 54 int u, v; 55 for (int i = 0; i < m; ++i) { 56 scanf("%d%d", &u, &v); 57 u--; v--; 58 G[u].push_back(v); 59 } 60 find_scc(n); 61 M(G2, 0); 62 for (int i = 0; i < n; ++i) 63 for (int j = 0; j < G[i].size(); ++j) { 64 int k = G[i][j]; 65 if (sccno[i] != sccno[k]) G2[sccno[i]][sccno[k]] = true; 66 } 67 int ans = 0; 68 for (int i = 1; i <= scc_cnt; ++i) 69 ans = max(ans, dp(i)+val[i]); 70 printf("%d\n", ans); 71 } 72 73 74 return 0; 75 }