ZOJ 3795:Grouping(缩点+最长路)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5303

题意:有n个人m条边,每条边有一个u,v,代表u的年龄大于等于v,现在要将这n个人分成x个组,组内的人的年龄不能够直接或者间接比较,问最少可以分成多少组。

思路:一开始没看清题意,直接拓扑排序做了。后来听师兄说会有环,年龄大于等于,如果有环代表这里面的年龄相等,那么环里面的人都是每个人一组,缩完点之后那个点的长度就是点的人数,然后用DP最长路做。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <string>
 6 #include <cmath>
 7 #include <queue>
 8 #include <vector>
 9 #include <map>
10 #include <set>
11 #include <stack>
12 using namespace std;
13 #define INF 0x3f3f3f3f
14 #define N 100010
15 struct Edge {
16     int v, nxt;
17 } edge[N*3], edg[N*3];
18 int cnt[N], dp[N], head[N], hea[N], tott, tot, tim, vis[N], deg[N], dfn[N], low[N], belong[N], num;
19 stack<int> sta;
20
21 void Add(int u, int v) {
22     edge[tot].v = v; edge[tot].nxt = head[u]; head[u] = tot++;
23 }
24
25 void add(int u, int v) {
26     edg[tott].v = v; edg[tott].nxt = hea[u]; hea[u] = tott++;
27 }
28
29 void tarjan(int u) {
30     dfn[u] = low[u] = ++tim;
31     sta.push(u); vis[u] = 1;
32     for(int i = head[u]; ~i; i = edge[i].nxt) {
33         Edge &e = edge[i];
34         if(!dfn[e.v]) {
35             tarjan(e.v);
36             if(low[e.v] < low[u]) low[u] = low[e.v];
37         } else if(vis[e.v] && dfn[e.v] < low[u]) low[u] = dfn[e.v];
38     }
39     if(low[u] == dfn[u]) {
40         ++num; int v = -1;
41         cnt[num] = 0;
42         while(v != u) {
43             v = sta.top(); sta.pop();
44             belong[v] = num;
45             cnt[num]++;
46             vis[v] = 0;
47         }
48     }
49 }
50
51 int DFS(int u) {
52     if(dp[u]) return dp[u];
53     int ans = cnt[u];
54     for(int i = hea[u]; ~i; i = edg[i].nxt) {
55         int v = edg[i].v;
56         ans = max(ans, DFS(v) + cnt[u]);
57     }
58     return dp[u] = ans;
59 }
60
61 int main() {
62     int n, m;
63     while(~scanf("%d%d", &n, &m)) {
64         memset(head, -1, sizeof(head));
65         memset(hea, -1, sizeof(hea));
66         memset(dfn, 0, sizeof(dfn));
67         memset(dp, 0, sizeof(dp));
68         tot = num = tott = tim = 0;
69         int u, v;
70         for(int i = 0; i < m; i++) {
71             scanf("%d%d", &u, &v);
72             Add(u, v);
73         }
74         for(int i = 1; i <= n; i++)
75             if(!dfn[i]) tarjan(i);
76         for(int u = 1; u <= n; u++) {
77             for(int i = head[u]; ~i; i = edge[i].nxt) {
78                 int v = edge[i].v;
79                 if(belong[u] != belong[v]) {
80                     add(belong[u], belong[v]);
81                 }
82             }
83         }
84         int ans = 0;
85         for(int i = 1; i <= num; i++)
86             ans = max(ans, DFS(i));
87         printf("%d\n", ans);
88     }
89     return 0;
90 }
时间: 2024-11-09 01:05:04

ZOJ 3795:Grouping(缩点+最长路)的相关文章

ZOJ 3795 Grouping 强连通分量-tarjan

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

ZOJ 3795 Grouping(强联通分量 + 缩点 + Dp)

Problem Description: Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-th message shows that the age of person si is not smaller than the age of person ti. Now we need to divide all these N people into

ZOJ 3795 Grouping

Grouping Time Limit: 2 Seconds      Memory Limit: 65536 KB Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-th message shows that the age of person si is not smaller than the age of person ti. Now we

[SDOI2010]所驼门王的宝藏 --tarjan缩点+最长路

[SDOI2010]所驼门王的宝藏 题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为“先知”的Alpaca L. Sotomon是这个家族的领袖,外人也称其为“所驼门王”.所驼门王毕生致力于维护家族的安定与和谐,他曾亲自率军粉碎河蟹帝国主义的野蛮侵略,为族人立下赫赫战功.所驼门王一生财宝无数,但因其生性节俭低调,他将财宝埋藏在自己设计的地下宫殿里,这也是今天Henry Curtis故事的起点.Henry是一个爱财如命的贪婪家伙,而又非常聪明,他费尽心机谋划了这次盗窃行动,

zoj 5303 Grouping 缩点求最长路

点击打开链接 Grouping Time Limit: 2 Seconds      Memory Limit: 65536 KB Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-th message shows that the age of person si is not smaller than the age of person ti.

ZOJ 3795 Grouping 强联通缩点+拓扑序+偏序集的最大链的大小

题意:有n个人,m个关系,关系是这两个人前一个人可以跟后一个比较. 那么问你我最少分多少组可以使这个组里的人都不可以比较. 只会强联通缩点,真特么不知道怎么做,想了一个小时,网上一看,还要会偏序集的东西,有一个叫Dilworth定理的东西. 定理1 令(X,≤)是一个有限偏序集,并令r是其最大链的大小.则X可以被划分成r个但不能再少的反链. 其对偶定理称为Dilworth定理: 定理2 令(X,≤)是一个有限偏序集,并令m是反链的最大的大小.则X可以被划分成m个但不能再少的链. 然后我们用到的是

ZOJ 3795 Grouping(Tarjan缩点+DAG)

Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-th message shows that the age of person si is not smaller than the age of person ti. Now we need to divide all these N people into several groups. One'

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

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

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

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