UVAoj 11324 - The Largest Clique(tarjan + dp)

题意:给定一个有向图,寻找一个点数最大集合,使得这个集合中的任意两个点
u,v, 都有u->v 或者 v->u 或者u<==>v

思路:首先将强连通分量通过tarjan算法求出来,然后进行缩点,也就是每一个缩点
所组成的图就是一个DAG图!令每一个点的权值就是这个缩点所包含节点(也就是对应的
强连通分量的节点数目),因为强连通分量的任意的两个节点都是相互可达的,那么这个
缩点要么选要么不选,问题就转换成了DAG图上的最长路径!

  1 #include<iostream>
  2 #include<queue>
  3 #include<stack>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<algorithm>
  7 #include<vector>
  8 #define N 1005
  9 using namespace std;
 10
 11 struct EDGE{
 12     int u, v, nt;
 13     EDGE(){}
 14     EDGE(int u, int v, int nt) : u(u), v(v), nt(nt){}
 15 };
 16
 17 int first[N];
 18 vector<EDGE>g;
 19 vector<EDGE>gg;
 20 int scc_cnt, dfs_clock;
 21 int scc[N];
 22 int pre[N], low[N];
 23 int dp[N], cnt[N];
 24
 25 int in[N];
 26 int n, m;
 27 stack<int>s;
 28
 29 void dfs(int u){
 30     pre[u] = low[u] = ++dfs_clock;
 31     s.push(u);
 32     for(int i = first[u]; ~i; i = g[i].nt){
 33         int v = g[i].v;
 34         if(!pre[v]){
 35             dfs(v);
 36             low[u] = min(low[u], low[v]);
 37         }else if(!scc[v])
 38             low[u] = min(low[u], pre[v]);
 39     }
 40     if(low[u] == pre[u]){
 41         ++scc_cnt;
 42         while(1){
 43             ++cnt[scc_cnt];
 44             int x = s.top(); s.pop();
 45             scc[x] = scc_cnt;
 46             if(x==u) break;
 47         }
 48     }
 49 }
 50
 51 void addEdge(int u, int v){
 52     g.push_back(EDGE(u, v, first[u]));
 53     first[u] = g.size() - 1;
 54 }
 55
 56 void tarjans(){
 57     memset(pre, 0, sizeof(pre));
 58     memset(scc, 0, sizeof(scc));
 59     memset(cnt, 0, sizeof(cnt));
 60     memset(dp, 0, sizeof(dp));
 61     memset(in, 0, sizeof(in));
 62     scc_cnt = 0;
 63     dfs_clock = 0;
 64     for(int i=1; i<=n; ++i)
 65         if(!pre[i]) dfs(i);
 66     int len = g.size();
 67     memset(first, -1, sizeof(first));
 68     gg.clear();
 69     for(int i=0; i<len; ++i)
 70         if(scc[g[i].u] != scc[g[i].v]){
 71              in[scc[g[i].v]]++;
 72              gg.push_back(EDGE(scc[g[i].u], scc[g[i].v], first[scc[g[i].u]]));
 73              first[scc[g[i].u]] = gg.size() - 1;
 74         }
 75     int maxN = 0;
 76     queue<int>q;
 77     for(int i=1; i<=scc_cnt; ++i)
 78         if(!in[i]){
 79            dp[i] = cnt[i];
 80            q.push(i);
 81            if(maxN < dp[i]) maxN = dp[i];
 82         }
 83     while(!q.empty()){
 84         int u = q.front(); q.pop();
 85         for(int i=first[u]; ~i; i = gg[i].nt){
 86             int v = gg[i].v;
 87             dp[v] = max(dp[v], dp[u] + cnt[v]);
 88             q.push(v);
 89             if(maxN < dp[v]) maxN = dp[v];
 90         }
 91     }
 92     printf("%d\n", maxN);
 93 }
 94
 95 int main(){
 96     int t;
 97     scanf("%d", &t);
 98     while(t--){
 99         memset(first, -1, sizeof(first));
100         scanf("%d%d", &n, &m);
101         while(m--){
102             int u, v;
103             scanf("%d%d", &u, &v);
104             addEdge(u, v);
105         }
106         tarjans();
107         g.clear();
108     }
109     return 0;
110 } 

时间: 2024-10-10 21:39:12

UVAoj 11324 - The Largest Clique(tarjan + dp)的相关文章

UVA 11324.The Largest Clique tarjan缩点+拓扑dp

题目链接:https://vjudge.net/problem/UVA-11324 题意:求一个有向图中结点数最大的结点集,使得该结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以). 思路:同一个强联通分量中满足结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以).把强联通分量收缩点后得到scc图,让每个scc结点的权值等于他的结点数,则求scc图上权最大的路径.拓扑dp,也可以直接bfs,但是要建立一个新的起点,连接所有入度为0

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

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

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

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

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

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

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

uva 11324 The Largest Clique(图论-tarjan,动态规划)

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

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的边 方法: 先找强连通分量缩点,每个强连通分量显然满足条件,然后在缩点后的图中找到一条权值最大的路径,权值为此路径的点权之和,点权为这个

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

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