zoj Grouping(强连通+缩点+关键路径)

  题意:

    给你N个人,M条年龄大小的关系,现在打算把这些人分成不同的集合,使得每个集合的任意两个人之间的年龄是不可比的。问你最小的集合数是多少?

  分析:

    首先,假设有一个环,那么这个环中的任意两个点之间都是可比的,并且,和这个环相连的任意一个点或环也和这个环是可比的,因为关系具有传递性。但如果两个点或者环,无法处在同一条路径上,那么这两个点和环就是不可比的。所以,如果我们把这些环--强连通分量缩为一个点。强连通分量的点数就是缩点后的点权。那么缩点后的新图就是一个有向带权无环图,题目就是要求我们求出这个有向带权无环图的关键路径----最长路径。(因为那些较短的路径上的点总可以和较长的路径点和为一点)。

  1 //First Edit Time:    2014-11-25 13:38
  2 //Last Edit Time:    2014-11-25 14:24
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<vector>
  6 using namespace std;
  7
  8 #define _clr(x, y) memset(x, y, sizeof (x))
  9 #define Min(x, y) (x < y ? x : y)
 10 #define Max(x, y) (x > y ? x : y)
 11 #define INF 0x3f3f3f3f
 12 #define N  100010
 13
 14 vector<int> map[N], new_map[N];
 15 int low[N], dfn[N];
 16 int Stack[N], be[N];
 17 bool instack[N];
 18 int dist[N], sum[N];
 19 int top, n, cnt, time;
 20
 21 void Init()
 22 {
 23     top = time = cnt = 0;
 24     _clr(instack, 0);
 25     _clr(Stack, 0);
 26     _clr(dist, -1);
 27     _clr(low, 0);
 28     _clr(sum, 0);
 29     _clr(dfn, 0);
 30     _clr(be, 0);
 31     for(int i=0; i<=n; i++)
 32     {
 33         map[i].clear();
 34         new_map[i].clear();
 35     }
 36 }
 37
 38 //dfs生成树求强连通分量
 39 void dfs(int u)
 40 {
 41     dfn[u] = low[u] = ++time;
 42     Stack[top++] = u;
 43     instack[u] = true;
 44     for(int i=0; i<(int)map[u].size(); i++)
 45     {
 46         int v = map[u][i];
 47         if(!dfn[v])
 48         {
 49             dfs(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     if(dfn[u]==low[u])
 56     {
 57         cnt++;
 58         do
 59         {
 60             u = Stack[--top];
 61             instack[u] = false;
 62             be[u] = cnt;
 63             sum[cnt]++;
 64         }while(dfn[u] != low[u]);
 65     }
 66 }
 67
 68 void Tarjan_Scc()
 69 {
 70     for(int i=1; i<=n; i++)
 71     {
 72         if(!dfn[i])
 73             dfs(i);
 74     }
 75     for(int i=1; i<=n; i++)
 76     {
 77         for(int j=0; j<(int)map[i].size(); j++)
 78         {
 79             int v = map[i][j];
 80             if(be[i] != be[v])
 81                 new_map[be[i]].push_back(be[v]);
 82         }
 83     }
 84 }
 85
 86 int Get(int u)
 87 {
 88     if(dist[u]!=-1) return dist[u];
 89     dist[u] = 0;
 90     for(int i=0; i<(int)new_map[u].size(); i++)
 91         dist[u] = Max(Get(new_map[u][i]), dist[u]);
 92     return dist[u] = dist[u] + sum[u];
 93 }
 94
 95 int main()
 96 {
 97     int m, x, y;
 98     while(~scanf("%d%d",&n,&m))
 99     {
100         Init();
101         for(int i=0; i<m; i++)
102         {
103             scanf("%d%d",&x, &y);
104             map[x].push_back(y);
105         }
106
107         Tarjan_Scc();       //Tarjan算法求强连通缩点为一个DAG
108
109         int ans = -INF;
110         for(int i=1; i<=cnt; i++)   //记忆化搜索求DAG关键路径
111            ans = Max(Get(i), ans);
112
113         printf("%d\n", ans);
114     }
115     return 0;
116 }
时间: 2024-08-05 20:24:49

zoj Grouping(强连通+缩点+关键路径)的相关文章

ZOJ3795 Grouping 强连通缩点+图的最长路

给出m条a年龄大于等于b的信息,要求可以比较的两个人不能放在同一组,问最少能分成几组. 由于是大于等于,所以原图可能构成强连通分量,意思就是有很多人年龄相同(想想也该知道,总共10w个人,肯定有很多人年龄重复= =!)将原图缩点后,对新图记忆化搜索求最长路. 如果不缩点,会RE... #include <iostream> #include<cstring> #include<cstdio> #include<string> #include<algo

ZOJ 3795 Grouping 强连通分量-tarjan

一开始我还天真的一遍DFS求出最长链以为就可以了 不过发现存在有向环,即强连通分量SCC,有向环里的每个点都是可比的,都要分别给个集合才行,最后应该把这些强连通分量缩成一个点,最后保证图里是 有向无环图才行,这个时候再找最长链,当然缩点之后的scc是有权值的,不能只看成1,缩点完了之后,用记忆化搜索DP就可以再On的复杂度内求出结果 所以现学了一下SCC-Tarjan,所谓Scc-tarjan,就是找到强连通分量并且缩点,特别好用,其原理就是利用dfs时间戳,每个点有自己的时间戳,同时再开一个记

zoj3795 Grouping --- 强连通,求最长路

给定图,求把至少把图拆成几个集合能够使集合内的点没有直接或间接关系. 首先由题意可得图中可能含环,而环里面的点肯定是要拆开的. 缩点建图得DAG图,可以想象一下..把图从入度为零的点向下展开,位于同一层的点放在一个集合是没有关系的, 那么题目所求的问题就转化成求图中最长路的问题了. 这个题的实质和 这题 其实是一模一样的.. #include <iostream> #include <cstring> #include <string> #include <cst

Light OJ 1168 Wishing Snake 强连通缩点+哈密顿通路

题目来源:Light OJ 1168 Wishing Snake 题意:有点难看懂题意 看了一个小时再加别人的代码才懂意思 从0开始 输入的那些每一对u v 都要经过 就是从0到到达那些点 思路:首先缩点 每一个强连通分量里面的点都是可达的 缩点后的图是有向无环图 如果从0这个强连通分量可以出去到2个强连通分量 那么这两个强连通分量是不可能相互可达 所以可行的方案就是所有的强连通分量连成一线 一个一个串起来 除了第一个 出度是1入度是0和最后一个出度是0入度是1 其他都是入度等于出度是1 特判只

强连通缩点— HDU1827

强连通缩点以后最终形成的是一棵树 我们可以根据树的性质来看缩点以后的强连通分量图,就很好理解了 /* gyt Live up to every day */ #include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<stack> #include<cstring> #include<

BZOJ 1051: [HAOI2006]受欢迎的牛 强连通缩点

题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1051 题解: 强连通缩点得到DAG图,将图转置一下,对入度为零的点跑dfs看看能不能访问到所有的点. 代码: #include<iostream> #include<cstdio> #include<vector> #include<stack> #include<algorithm> #include<cstring> u

POJ3352Road Construction(边的双连通+强连通缩点)

Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8673   Accepted: 4330 Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the ro

hdu3861The King’s Problem (强连通 缩点+最小路径覆盖)

The King's Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1606 Accepted Submission(s): 584 Problem Description In the Kingdom of Silence, the king has a new problem. There are N cities in

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

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