Uva 11324 The Largest Clique【强连通 DAG动规 spfa】

白书上的例题

做一遍tarjan后,缩点,每一个scc节点的权为它的结点数,做一次DAG上的动规,求出路径上的最大点权和,就可以了

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<stack>
  6 #include<vector>
  7 using namespace std;
  8
  9 const int maxn = 5005;
 10 int n,m;
 11 int first[maxn];
 12 int sc[maxn],scn[maxn],low[maxn],pre[maxn];
 13 int scnt,ecnt,dfs_clock;
 14 int dp[maxn];
 15
 16 int first1[maxn];
 17 int ecnt1;
 18
 19 struct Edge{
 20     int v,next;
 21 }e[maxn*10];
 22
 23 Edge e1[maxn*10];
 24
 25 stack<int> S;
 26
 27 void init(){
 28     ecnt = ecnt1 = 0;
 29     memset(first,-1,sizeof(first));
 30     memset(first1,-1,sizeof(first1));
 31     memset(dp,0,sizeof(dp));
 32 }
 33
 34 void addedges(int u,int v){
 35     e[ecnt].v = v;
 36     e[ecnt].next = first[u];
 37     first[u] = ecnt++;
 38 }
 39
 40 void addedges1(int u,int v){
 41     e1[ecnt1].v = v;
 42     e1[ecnt1].next = first1[u];
 43     first1[u] = ecnt1++;
 44 }
 45
 46 void dfs(int u){
 47     low[u] = pre[u] = ++dfs_clock;
 48     S.push(u);
 49     for(int i = first[u];~i;i = e[i].next){
 50         int v = e[i].v;
 51         if(!pre[v]){
 52             dfs(v);
 53             low[u] = min(low[u],low[v]);
 54         }
 55         else if(!sc[v]) low[u] = min(low[u],pre[v]);
 56     }
 57     if(pre[u] == low[u]){
 58         scnt++;
 59         for(;;){
 60             int x = S.top();S.pop();
 61             sc[x] = scnt;
 62             scn[scnt]++;
 63             if(x == u) break;
 64         }
 65     }
 66 }
 67
 68 void find_scc(){
 69     while(!S.empty()) S.pop();
 70     scnt = dfs_clock = 0;
 71     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
 72     memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn));
 73
 74     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
 75 }
 76
 77 int solve(int p){
 78     if(dp[p]) return dp[p];
 79     for(int i = first1[p];~i;i = e1[i].next){
 80         int v = e1[i].v;
 81         dp[p] = max(dp[p],solve(v));
 82     }
 83     return dp[p] = dp[p] + scn[p];
 84 }
 85
 86
 87 int main(){
 88     int T;
 89     scanf("%d",&T);
 90     while(T--){
 91         init();
 92         scanf("%d %d",&n,&m);
 93         for(int i = 0;i < m;i++ ){
 94             int u,v;
 95             scanf("%d %d",&u,&v);
 96             addedges(u,v);
 97         }
 98         find_scc();
 99
100         for(int u = 1;u <= n;u++){
101             for(int i = first[u];~i;i = e[i].next){
102                 int v = e[i].v;
103                 if(sc[u] != sc[v]) addedges1(sc[u],sc[v]);
104             }
105         }
106
107
108         int ans = 0;
109         for(int i = 1;i <= scnt;i++) ans = max(ans,solve(i));
110         printf("%d\n",ans);
111     }
112     return 0;
113 }

还有另一种做法是,建立一个超级源点,与入度为0的scc节点连接,做一次spfa,求出路径上的最大点权和

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<stack>
  6 #include<vector>
  7 #include<queue>
  8 using namespace std;
  9
 10 const int maxn = 5005;
 11 const int INF = 1000000005;
 12 int n,m;
 13 int first[maxn];
 14 int sc[maxn],scn[maxn],low[maxn],pre[maxn];
 15 int scnt,ecnt,dfs_clock;
 16 int dp[maxn];
 17
 18 int du[maxn];
 19 int dis[maxn];
 20 int inq[maxn];
 21
 22 int first1[maxn];
 23 int ecnt1;
 24
 25 struct Edge{
 26     int v,next;
 27 }e[maxn*10];
 28
 29 Edge e1[maxn*10];
 30
 31 stack<int> S;
 32 vector<int> g[maxn];
 33 int val[maxn];
 34
 35 void init(){
 36     ecnt = ecnt1 = 0;
 37     memset(first,-1,sizeof(first));
 38     memset(val,0,sizeof(val));
 39     memset(du,0,sizeof(du));
 40 }
 41
 42 void addedges(int u,int v){
 43     e[ecnt].v = v;
 44     e[ecnt].next = first[u];
 45     first[u] = ecnt++;
 46 }
 47
 48 void dfs(int u){
 49     low[u] = pre[u] = ++dfs_clock;
 50     S.push(u);
 51     for(int i = first[u];~i;i = e[i].next){
 52         int v = e[i].v;
 53         if(!pre[v]){
 54             dfs(v);
 55             low[u] = min(low[u],low[v]);
 56         }
 57         else if(!sc[v]) low[u] = min(low[u],pre[v]);
 58     }
 59     if(pre[u] == low[u]){
 60         scnt++;
 61         for(;;){
 62             int x = S.top();S.pop();
 63             sc[x] = scnt;
 64             val[scnt]++;
 65             if(x == u) break;
 66         }
 67     }
 68 }
 69
 70 void find_scc(){
 71     while(!S.empty()) S.pop();
 72     scnt = dfs_clock = 0;
 73     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
 74     memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn));
 75
 76     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
 77 }
 78
 79
 80 int spfa(){
 81     memset(inq, 0, sizeof(inq));
 82     queue<int>q;
 83     g[0].clear();
 84     q.push(0);
 85     dis[0] = 0; val[0] = 0;
 86     for(int i = 1; i <= scnt; i++){if(du[i] == 0)g[0].push_back(i); dis[i] = -INF;}
 87     int ans = 0;
 88     while(!q.empty()){
 89         int u = q.front(); q.pop(); inq[u] = 0;
 90         for(int i = 0; i < g[u].size(); i++){
 91             int v = g[u][i];
 92             if(dis[v] < dis[u] + val[v]){
 93                 dis[v] = dis[u] + val[v];
 94                 ans = max(ans, dis[v]);
 95                 if(inq[v] == 0)inq[v] = 1, q.push(v);
 96             }
 97         }
 98     }
 99     return ans;
100 }
101
102 int main(){
103     int T;
104     scanf("%d",&T);
105     while(T--){
106         init();
107         scanf("%d %d",&n,&m);
108         for(int i = 0;i < m;i++ ){
109             int u,v;
110             scanf("%d %d",&u,&v);
111             addedges(u,v);
112         }
113         find_scc();
114         for(int i = 1;i <= scnt;i++) g[i].clear();
115
116         for(int u = 1;u <= n;u++){
117             for(int i = first[u];~i;i = e[i].next){
118                 int v = e[i].v;
119                 if(sc[u] != sc[v]) g[sc[u]].push_back(sc[v]),du[sc[v]]++;
120             }
121         }
122         printf("%d\n",spfa());
123     }
124     return 0;
125 }

时间: 2024-10-11 06:10:56

Uva 11324 The Largest Clique【强连通 DAG动规 spfa】的相关文章

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

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

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

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

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(图论-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 (DAG + 强连通分量)

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

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