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 }

 

posted @ 2017-04-15 22:17  Robin!  阅读(223)  评论(0编辑  收藏  举报