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

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

题解:

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

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

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

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

  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
", ans);
131     }
132 }
View Code

前向星建图 + vector重建:

  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
", ans);
132     }
133 }
View Code

vector建图 + vector重建:

  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
", ans);
119     }
120 }
View Code
原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7820041.html