题目链接:​​https://vjudge.net/problem/UVA-11324​

 

UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP_i++

UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP_ios_02

 

题解:

题意:给出一张有向图,求一个结点数最大的结点集,使得任意两个结点u、v,要么u能到达v, 要么v能到达u(u和v也可以互相到达)。

1.可知在一个强连通分量中,任意两个点都可以互相到达。那么我们就对每个强连通分量进行缩点,并记录每个分量的结点个数。

2.缩点之后,就是一张有向无环图了,这时就转化为求:从有向无环图中找出一条权值之和最大的路径。简单的记忆化搜索即可实现。

 

 

前向星建图 + 前向星重建:


UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP_i++_03UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP_#include_04


1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <cmath>
5 #include <algorithm>
6 #include <vector>
7 #include <queue>
8 #include <stack>
9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const double EPS = 1e-8;
15 const int INF = 2e9;
16 const LL LNF = 2e18;
17 const int MAXM = 5e4+10;
18 const int MAXN = 1e3+10;
19
20 struct Edge
21 {
22 int to, next;
23 }edge[MAXM], edge0[MAXM]; //edge为初始图, edge0为重建图
24 int tot, head[MAXN], tot0, head0[MAXN];
25
26 int Index, dfn[MAXN], low[MAXN];
27 int top, Stack[MAXN], instack[MAXN];
28 int scc, belong[MAXN], num[MAXN];
29 int dp[MAXN];
30
31 void addedge(int u, int v, Edge edge[], int head[], int &tot)
32 {
33 edge[tot].to = v;
34 edge[tot].next = head[u];
35 head[u] = tot++;
36 }
37
38 void Tarjan(int u)
39 {
40 dfn[u] = low[u] = ++Index;
41 Stack[top++] = u;
42 instack[u] = true;
43 for(int i = head[u]; i!=-1; i = edge[i].next)
44 {
45 int v = edge[i].to;
46 if(!dfn[v])
47 {
48 Tarjan(v);
49 low[u] = min(low[u], low[v]);
50 }
51 else if(instack[v])
52 low[u] = min(low[u], dfn[v]);
53 }
54
55 if(dfn[u]==low[u])
56 {
57 int v;
58 scc++;
59 do
60 {
61 v = Stack[--top];
62 instack[v] = false;
63 belong[v] = scc;
64 num[scc]++;
65 }while(v!=u);
66 }
67 }
68
69 int dfs(int u)
70 {
71 if(dp[u]!=-1) return dp[u];
72 dp[u] = num[u];
73 for(int i = head0[u]; i!=-1; i = edge0[i].next)
74 {
75 int v = edge0[i].to;
76 dp[u] = max(dp[u], num[u]+dfs(v));
77 }
78 return dp[u];
79 }
80
81 void init()
82 {
83 tot = tot0 = 0;
84 memset(head, -1, sizeof(head));
85 memset(head0, -1, sizeof(head0));
86
87 Index = top = 0;
88 memset(dfn, 0, sizeof(dfn));
89 memset(low, 0, sizeof(low));
90 memset(instack, 0, sizeof(instack));
91
92 scc = 0;
93 memset(num, 0, sizeof(num));
94 memset(dp, -1, sizeof(dp));
95 }
96
97 int main()
98 {
99 int n, m, T;
100 scanf("%d", &T);
101 while(T--)
102 {
103 scanf("%d%d", &n, &m);
104 init();
105 for(int i = 1; i<=m; i++)
106 {
107 int u, v;
108 scanf("%d%d", &u, &v);
109 addedge(u, v, edge, head, tot);
110 }
111
112 for(int i = 1; i<=n; i++)
113 if(!dfn[i])
114 Tarjan(i);
115
116 for(int u = 1; u<=n; u++) //重建建图
117 for(int i = head[u]; i!=-1; i = edge[i].next)
118 {
119 int tmpu = belong[u];
120 int tmpv = belong[edge[i].to];
121 if(tmpu!=tmpv)
122 addedge(tmpu, tmpv, edge0, head0, tot0);
123 }
124
125 int ans = 0;
126 for(int i = 1; i<=scc; i++)
127 if(dp[i]==-1)
128 ans = max(ans, dfs(i));
129
130 printf("%d\n", ans);
131 }
132 }

View Code

 

前向星建图 + vector重建:


UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP_i++_03UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP_#include_04


1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <cmath>
5 #include <algorithm>
6 #include <vector>
7 #include <queue>
8 #include <stack>
9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const double EPS = 1e-8;
15 const int INF = 2e9;
16 const int MAXM = 5e4+10;
17 const int MAXN = 1e3+10;
18
19 struct Edge
20 {
21 int to, next;
22 }edge[MAXM];
23 int tot, head[MAXN];
24 vector<int>g[MAXN];
25
26 int Index, dfn[MAXN], low[MAXN];
27 int top, Stack[MAXN], instack[MAXN];
28 int scc, belong[MAXN], num[MAXN];
29 int dp[MAXN];
30
31 void addedge(int u, int v)
32 {
33 edge[tot].to = v;
34 edge[tot].next = head[u];
35 head[u] = tot++;
36 }
37
38 void Tarjan(int u)
39 {
40 dfn[u] = low[u] = ++Index;
41 Stack[top++] = u;
42 instack[u] = true;
43 for(int i = head[u]; i!=-1; i = edge[i].next)
44 {
45 int v = edge[i].to;
46 if(!dfn[v])
47 {
48 Tarjan(v);
49 low[u] = min(low[u], low[v]);
50 }
51 else if(instack[v])
52 low[u] = min(low[u], dfn[v]);
53 }
54
55 if(dfn[u]==low[u])
56 {
57 int v;
58 scc++;
59 do
60 {
61 v = Stack[--top];
62 instack[v] = false;
63 belong[v] = scc;
64 num[scc]++;
65 }while(v!=u);
66 }
67 }
68
69 int dfs(int u)
70 {
71 if(dp[u]!=-1) return dp[u];
72 dp[u] = num[u];
73 for(int i = 0; i<g[u].size(); i++)
74 {
75 int v = g[u][i];
76 dp[u] = max(dp[u], num[u]+dfs(v));
77 }
78 return dp[u];
79 }
80
81 void init(int n)
82 {
83 tot = 0;
84 memset(head, -1, sizeof(head));
85
86 Index = top = 0;
87 memset(dfn, 0, sizeof(dfn));
88 memset(low, 0, sizeof(low));
89 memset(instack, 0, sizeof(instack));
90
91 scc = 0;
92 memset(num, 0, sizeof(num));
93 memset(dp, -1, sizeof(dp));
94 for(int i = 1; i<=n; i++)
95 g[i].clear();
96 }
97
98 int main()
99 {
100 int n, m, T;
101 scanf("%d", &T);
102 while(T--)
103 {
104 scanf("%d%d", &n, &m);
105 init(n);
106 for(int i = 1; i<=m; i++)
107 {
108 int u, v;
109 scanf("%d%d", &u, &v);
110 addedge(u, v);
111 }
112
113 for(int i = 1; i<=n; i++)
114 if(!dfn[i])
115 Tarjan(i);
116
117 for(int u = 1; u<=n; u++)
118 for(int i = head[u]; i!=-1; i = edge[i].next)
119 {
120 int tmpu = belong[u];
121 int tmpv = belong[edge[i].to];
122 if(tmpu!=tmpv)
123 g[tmpu].push_back(tmpv);
124 }
125
126 int ans = 0;
127 for(int i = 1; i<=scc; i++)
128 if(dp[i]==-1)
129 ans = max(ans, dfs(i));
130
131 printf("%d\n", ans);
132 }
133 }

View Code

 

vector建图 + vector重建:


UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP_i++_03UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP_#include_04


1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <cmath>
5 #include <algorithm>
6 #include <vector>
7 #include <queue>
8 #include <stack>
9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const double EPS = 1e-8;
15 const int INF = 2e9;
16 const int MAXN = 1e3+10;
17
18 vector<int>G[MAXN], g[MAXN];
19
20 int Index, dfn[MAXN], low[MAXN];
21 int top, Stack[MAXN], instack[MAXN];
22 int scc, belong[MAXN], num[MAXN];
23 int dp[MAXN];
24
25 void Tarjan(int u)
26 {
27 dfn[u] = low[u] = ++Index;
28 Stack[top++] = u;
29 instack[u] = true;
30 for(int i = 0; i<G[u].size(); i++)
31 {
32 int v = G[u][i];
33 if(!dfn[v])
34 {
35 Tarjan(v);
36 low[u] = min(low[u], low[v]);
37 }
38 else if(instack[v])
39 low[u] = min(low[u], dfn[v]);
40 }
41
42 if(dfn[u]==low[u])
43 {
44 int v;
45 scc++;
46 do
47 {
48 v = Stack[--top];
49 instack[v] = false;
50 belong[v] = scc;
51 num[scc]++;
52 }while(v!=u);
53 }
54 }
55
56 int dfs(int u)
57 {
58 if(dp[u]!=-1) return dp[u];
59 dp[u] = num[u];
60 for(int i = 0; i<g[u].size(); i++)
61 {
62 int v = g[u][i];
63 dp[u] = max(dp[u], num[u]+dfs(v));
64 }
65 return dp[u];
66 }
67
68 void init(int n)
69 {
70 Index = top = 0;
71 memset(dfn, 0, sizeof(dfn));
72 memset(low, 0, sizeof(low));
73 memset(instack, 0, sizeof(instack));
74
75 scc = 0;
76 memset(num, 0, sizeof(num));
77 memset(dp, -1, sizeof(dp));
78 for(int i = 1; i<=n; i++)
79 {
80 G[i].clear();
81 g[i].clear();
82 }
83 }
84
85 int main()
86 {
87 int n, m, T;
88 scanf("%d", &T);
89 while(T--)
90 {
91 scanf("%d%d", &n, &m);
92 init(n);
93 for(int i = 1; i<=m; i++)
94 {
95 int u, v;
96 scanf("%d%d", &u, &v);
97 G[u].push_back(v);
98 }
99
100 for(int i = 1; i<=n; i++)
101 if(!dfn[i])
102 Tarjan(i);
103
104 for(int u = 1; u<=n; u++)
105 for(int i = 0; i<G[u].size(); i++)
106 {
107 int tmpu = belong[u];
108 int tmpv = belong[G[u][i]];
109 if(tmpu!=tmpv)
110 g[tmpu].push_back(tmpv);
111 }
112
113 int ans = 0;
114 for(int i = 1; i<=scc; i++)
115 if(dp[i]==-1)
116 ans = max(ans, dfs(i));
117
118 printf("%d\n", ans);
119 }
120 }

View Code