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的边

方法:

先找强连通分量缩点,每个强连通分量显然满足条件,然后在缩点后的图中找到一条权值最大的路径,权值为此路径的点权之和,点权为这个强连通分量的点数

1 int dp[maxn];
2 int dfs(int u)
3 {
4     if (dp[u]) return dp[u];
5     int ret = 0;
6     for (int i = head[u]; ~i; i = edge[i].next)
7         ret = max(ret, dfs(edge[i].v));
8     return dp[u] = ret + node[u];
9 }

代码:

  1 /********************************************
  2 *ACM Solutions
  3 *
  4 *@Title:
  5 *@Version: 1.0
  6 *@Time: 2014-xx-xx
  7 *@Solution: http://www.cnblogs.com/xysmlx/p/xxxxxxx.html
  8 *
  9 *@Author: xysmlx(Lingxiao Ma)
 10 *@Blog: http://www.cnblogs.com/xysmlx
 11 *@EMail: [email protected]
 12 *
 13 *Copyright (C) 2011-2015 xysmlx(Lingxiao Ma)
 14 ********************************************/
 15 // #pragma comment(linker, "/STACK:102400000,102400000")
 16 #include <cstdio>
 17 #include <iostream>
 18 #include <cstring>
 19 #include <string>
 20 #include <cmath>
 21 #include <set>
 22 #include <list>
 23 #include <map>
 24 #include <iterator>
 25 #include <cstdlib>
 26 #include <vector>
 27 #include <queue>
 28 #include <ctime>
 29 #include <stack>
 30 #include <algorithm>
 31 #include <functional>
 32 using namespace std;
 33 typedef long long ll;
 34 #define pb push_back
 35 #define ROUND(x) round(x)
 36 #define FLOOR(x) floor(x)
 37 #define CEIL(x) ceil(x)
 38 const int maxn = 1010;
 39 const int maxm = 200010;
 40 const int inf = 0x3f3f3f3f;
 41 const ll inf64 = 0x3f3f3f3f3f3f3f3fLL;
 42 const double INF = 1e30;
 43 const double eps = 1e-6;
 44 int kase;
 45 int n, m;
 46 struct Edge
 47 {
 48     int u, v;
 49     int next;
 50     Edge(int _u, int _v, int _next): u(_u), v(_v), next(_next) {}
 51     Edge() {}
 52 } edge[maxm];
 53 int en;
 54 int head[maxn];
 55 int node[maxn];
 56 void addse(int u, int v)
 57 {
 58     edge[en] = Edge(u, v, head[u]);
 59     head[u] = en++;
 60 }
 61 struct SCC
 62 {
 63     Edge edge[maxm];
 64     int en;
 65     int head[maxn];
 66     int h[maxn];
 67     void addse(int u, int v)
 68     {
 69         edge[en] = Edge(u, v, head[u]);
 70         head[u] = en++;
 71     }
 72     void init()
 73     {
 74         memset(head, -1, sizeof(head));
 75         en = 0;
 76     }
 77     int sid[maxn];
 78     int mark[maxn], low[maxn];
 79     int check[maxn];
 80     int sstack[maxn], top;
 81     int dfn, ssn;
 82     int n, m;
 83     bool mtx[maxn][maxn];
 84     void dfs(int k)
 85     {
 86         int i, j;
 87         check[k] = 1;
 88         low[k] = mark[k] = dfn++;
 89         sstack[top++] = k;
 90         for (int i = head[k]; i != -1; i = edge[i].next)
 91         {
 92             int j = edge[i].v;
 93             if (mark[j] == 0)
 94             {
 95                 dfs(j);
 96                 low[k] = min(low[k], low[j]);
 97             }
 98             else if (check[j])
 99                 low[k] = min(low[k], mark[j]);
100         }
101         if (mark[k] == low[k])
102         {
103             while (sstack[--top] != k)
104             {
105                 check[sstack[top]] = 0;
106                 sid[sstack[top]] = ssn;
107             }
108             sid[k] = ssn;
109             check[k] = 0;
110             ++ssn;
111         }
112         return;
113     }
114     void tarjan()
115     {
116         ssn = 1;
117         dfn = 1;
118         top = 0;
119         memset(check, 0, sizeof(check));
120         memset(mark, 0, sizeof(mark));
121         for (int i = 0; i < n; ++i) if (mark[i] == 0) dfs(i);
122
123         memset(h, 0, sizeof(h));
124         for (int i = 0; i < n; i++)
125             h[sid[i]]++;
126         memset(mtx, 0, sizeof(mtx));
127         for (int i = 0; i < en; i++)
128             mtx[sid[edge[i].u]][sid[edge[i].v]] = 1;
129     }
130 } scc;
131
132 int dp[maxn];
133 int dfs(int u)
134 {
135     if (dp[u]) return dp[u];
136     int ret = 0;
137     for (int i = head[u]; ~i; i = edge[i].next)
138         ret = max(ret, dfs(edge[i].v));
139     return dp[u] = ret + node[u];
140 }
141
142 void init()
143 {
144     kase++;
145     scc.init();
146     memset(head, -1, sizeof(head));
147     en = 0;
148     memset(dp, 0, sizeof(dp));
149 }
150 void input()
151 {
152     scanf("%d%d", &n, &m);
153     scc.n = n;
154     for (int i = 0; i < m; i++)
155     {
156         int u, v;
157         scanf("%d%d", &u, &v);
158         u--, v--;
159         scc.addse(u, v);
160     }
161 }
162 void debug()
163 {
164     //
165 }
166 void solve()
167 {
168     scc.tarjan();
169     n = scc.ssn;
170     for (int i = 1; i < scc.ssn; i++)
171     {
172         for (int j = 1; j < scc.ssn; j++)
173         {
174             if (i == j) continue;
175             if (scc.mtx[i][j])
176                 addse(i, j);
177         }
178     }
179     for (int i = 1; i < scc.ssn; i++)
180         node[i] = scc.h[i];
181     // for (int i = 1; i < scc.ssn; i++)
182     //     cout << node[i] << " ";
183     // cout << endl;
184     int ans = 0;
185     memset(dp, 0, sizeof(dp));
186     for (int i = 1; i < n; i++)
187     {
188         ans = max(ans, dfs(i));
189     }
190     printf("%d\n", ans);
191 }
192 void output()
193 {
194     //
195 }
196 int main()
197 {
198     // 32-bit
199     // int size = 256 << 20; // 256MB
200     // char *p = (char *)malloc(size) + size;
201     // __asm__("movl %0, %%esp\n" :: "r"(p));
202
203     // 64-bit
204     // int size = 256 << 20; // 256MB
205     // char *p = (char *)malloc(size) + size;
206     // __asm__("movq %0, %%rsp\n" :: "r"(p));
207
208     // std::ios_base::sync_with_stdio(false);
209 #ifdef xysmlx
210     freopen("in.txt", "r", stdin);
211 #endif
212
213     kase = 0;
214     int T;
215     scanf("%d", &T);
216     while (T--)
217     {
218         init();
219         input();
220         solve();
221         output();
222     }
223     return 0;
224 }

UVA 11324

时间: 2024-10-12 04:03:47

UVA 11324 The Largest Clique (强连通分量缩点,图DP)的相关文章

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)

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

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

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

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 (强连通缩点+dp)

题目链接 题意:从有向图G中找到一个最大的点集,使得该点集中任意两个结点u,v满足u可达v或v可达u. 解法:先把同处于一个强连通分量中的结点合并(缩点),得到一张DAG图,在DAG上dp即可. 感觉自己的建图写得好丑啊,一直在纠结用数组还是结构体~~ 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 const int N=1e5+10; 5 int head[N],nxt[N],to[N],ne,n,m; 6 void addedge

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 <sta

UVA 11324 - The Largest Clique(强连通分量+缩点)

UVA 11324 - The Largest Clique 题目链接 题意:给定一个有向图,要求找一个集合,使得集合内任意两点(u, v)要么u能到v,要么v能到u,问最大能选几个点 思路:强连通分量,构造出scc之后,缩点,每个点的权值是集合点个数,然后做一遍dag找出最大权值路径即可 代码: #include <cstdio> #include <cstring> #include <vector> #include <stack> #include

UVA 11324 The Largest Clique (强连通缩点 + DAG最长路)

链接 : http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=30726 题意 : 有向图G,求一个最大的点集,使得点集中任意两个节点u和v,满足 要么u可以到达v,要么v可以到达u,或者u和v可以相互到达. 可以强连通缩点成一张DAG,以为每个强连通分量要么选要么不选.求DAG上的最长路 二次建图 用了2种不同的方法,也分别用了记忆花搜索DP和直接递推DP vector建图和记忆化搜索: #include <algorithm

UVA - 11324 The Largest Clique (DAG + 强连通分量)

题目大意:给出一张有向图G,求一个结点数最大的结点集,使得该点集中任意两个结点u和v满足: 要么u可到达v,要么v可以到达u(u和v互相可达也可以) 解题思路:u和v相互可达的时候,就是两个结点在同一个强连通分量内的时候 首先要保证集合里面的点可达:强连通分量就满足集合内的点都相互可达.所以第一件事就是找出所有的强连通分量,并统计出每个强连通分量内的结点数 然后找出每个强连通分量之间的关系,也就是找出两个强连通分量之间的桥,连接可连接的强连通分量 最后将每个强连通分量收缩,得到SCC图.此时的S