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

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

题解:

代码一:

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

代码二:

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

代码三:

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

时间: 2024-08-15 00:38:43

UVA11324 The Largest Clique —— 强连通分量 + 缩点 + DP的相关文章

UVA11324 The Largest Clique[强连通分量 缩点 DP]

UVA - 11324 The Largest Clique 题意:求一个节点数最大的节点集,使任意两个节点至少从一个可以到另一个 同一个SCC要选一定全选 求SCC 缩点建一个新图得到一个DAG,直接DP行了 这个新图不需要判重边,重边就是真实存在 // // main.cpp // 最大团 // // Created by Candy on 02/11/2016. // Copyright © 2016 Candy. All rights reserved. // #include <ios

uva 11324 The Largest Clique(强连通分量缩点+DAG动态规划)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=show_problem&problem=2299 题意:输入n和m,有n个点和m条有向边,求出一个节点集合包括的节点个数最多,而且该节点内的不论什么两点a,b,要么a能到达b,要么b能到达a,要么a和b互相到达. 思路:强连通分量缩点形成有向无环图DAG,把缩点后的每一个点的权值置为该强连通分量的节点个

UVA 11324 The Largest Clique (强连通分量缩点,图DP)

题目: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=show_problem&problem=2299 题意: 给你一个有向图,求一个点集合的最大大小,使得此点集合中对于任意点对(u,v),有从u到v或者从v到u的边 方法: 先找强连通分量缩点,每个强连通分量显然满足条件,然后在缩点后的图中找到一条权值最大的路径,权值为此路径的点权之和,点权为这个

uva11324 The Largest Clique --- 强连通+dp

给一个有向图G,求一个子图要求其中任意两点至少有一边可达, 问这个子图中最多含多少个顶点. 首先找SCC缩点建图,每个点的权值就是该点包含点的个数. 要求其中任意两点可达,实际上所有边只能同方向,不然一定有两点不可达, 这样题目又转换成求DAG图最长路的问题了. 然后从入度为0的点开始记忆化搜索,dp[i]表示以i为根最多包含多少点. #include <iostream> #include <cstring> #include <string> #include &l

UVa 11324 The Largest Clique (强连通分量+DP)

题意:给定一个有向图,求一个最大的结点集,使得任意两个结点,要么 u 能到 v,要么 v 到u. 析:首先,如果是同一个连通分量,那么要么全选,要么全不选,然后我们就可以先把强连通分量先求出来,然后缩成一个点,然后该图就成了一个DAG,然后就可以直接用DP来做了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #i

BZOJ 1179 Atm(强连通分量缩点+DP)

题目说可以通过一条边多次,且点权是非负的,所以如果走到图中的一个强连通分量,那么一定可以拿完这个强连通分量上的money. 所以缩点已经很明显了.缩完点之后图就是一个DAG,对于DAG可以用DP来求出到达每一个点的money最大值.具体实现我用的是bfs. 然后如果一个强连通分量内有酒馆,那么这个点就可以更新答案啦. # include <cstdio> # include <cstring> # include <cstdlib> # include <iost

UVA - 11324 The Largest Clique 强连通缩点+记忆化dp

题目要求一个最大的弱联通图. 首先对于原图进行强连通缩点,得到新图,这个新图呈链状,类似树结构. 对新图进行记忆化dp,求一条权值最长的链,每个点的权值就是当前强连通分量点的个数. /* Tarjan算法求有向图的强连通分量set记录了强连通分量 Col记录了强连通分量的个数. */ #include <iostream> #include<cstring> #include<cstdio> #include<string> #include<algo

UVa11324 - The Largest Clique(DAG+DP+SCC)

Problem B: The Largest Clique Given a directed graph G, consider the following transformation. First, create a new graph T(G) to have the same vertex set as G. Create a directed edge between two vertices u and v in T(G) if and only if there is a path

UVALIVE 4287 Proving Equivalences (强连通分量+缩点)

题意:给定一个图,问至少加入多少条边能够使这个图强连通. 思路:首先求出这个图的强连通分量.然后把每个强连通分量缩成一个点.那么这个图变成了一个DAG,求出全部点的入度和出度,由于强连通图中每个节点的入度和出度至少为1.那么我们求出入度为零的节点数量和出度为零的节点数量.答案取最大值,由于在一个DAG中加入这么多边一定能够使这个图强连通.注意当这个图本身强连通时要特判一下,答案为零. #include<cstdio> #include<cstring> #include<cm