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 several groups. One‘s age shouldn‘t be compared with each other in the same group, directly or indirectly. And everyone should be assigned to one and only one group. The task is to calculate the minimum number of groups that meet the
requirement.

Input:

There are multiple test cases. For each test case: The first line contains two integers
N(1≤ N≤ 100000), M(1≤ M≤ 300000),
N
is the number of people, and M is is the number of messages. Then followed by
M lines, each line contain two integers si and ti. There is a blank line between every two cases. Process to the end of input.

Output:

For each the case, print the minimum number of groups that meet the requirement one line.

Sample Input:

4 4

1 2

1 3

2 4

3 4

Sample Output:

3

解题思路:

强连通分量缩点,然后DP求最长路

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
const int MAXN = 100000 + 10;
vector<int>G[MAXN];
vector<int>RG[MAXN];
int vis[MAXN];
int pre[MAXN], lowlink[MAXN], sccno[MAXN];//点对应的强联通分量的编号
int dfs_clock, scc_cnt;//强联通分量的个数,编号为1~scc_cnt
int num[MAXN];//每个强联通分量所含的点的数目
stack<int>S;
void dfs(int u)
{
    pre[u] = lowlink[u] = ++dfs_clock;
    S.push(u);
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if(!pre[v])
        {
            dfs(v);
            lowlink[u] = min(lowlink[u], lowlink[v]);
        }
        else if(!sccno[v])
        {
            lowlink[u] = min(lowlink[u], pre[v]);
        }
    }
    if(lowlink[u] == pre[u])
    {
        scc_cnt++;
        for(;;)
        {
            int x = S.top();
            S.pop();
            sccno[x] = scc_cnt;
            num[scc_cnt]++;
            if(x == u) break;
        }
    }
}
void find_scc(int n)
{
    dfs_clock = scc_cnt = 0;
    memset(sccno, 0, sizeof(sccno));
    memset(pre, 0, sizeof(pre));
    memset(num, 0, sizeof(num));
    for(int i=0;i<n;i++)
    {
        if(!pre[i]) dfs(i);
    }
}
int dp[MAXN];
int DP(int u)
{
    if(dp[u] != -1)
        return dp[u];
    dp[u] = num[u];
    for(int i=0;i<RG[u].size();i++)
    {
        int v = RG[u][i];
        dp[u] = max(dp[u], num[u] + DP(v));
    }
    return dp[u];
}
int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m)!=EOF)
    {
        for(int i=0;i<n;i++)
            G[i].clear();
        int u, v;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d", &u, &v);
            u--; v--;
            G[u].push_back(v);
        }
        find_scc(n);
        for(int i=1;i<=scc_cnt;i++) RG[i].clear();
        for(int i=0;i<n;i++)
        {
            int sz = G[i].size();
            for(int j=0;j<sz;j++)
            {
                if(sccno[i] != sccno[G[i][j]])
                {
                    RG[sccno[i]].push_back(sccno[G[i][j]]);
                }
            }
        }
        int ans = 0;
        memset(dp, -1, sizeof(dp));
        for(int i=1;i<=scc_cnt;i++)
            ans = max(ans, DP(i));
        printf("%d\n", ans);
    }
    return 0;
}



时间: 2024-12-15 01:37:14

ZOJ 3795 Grouping(强联通分量 + 缩点 + Dp)的相关文章

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

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

【POJ1236】Network of Schools 强联通分量缩点(本文kosaraju)

/*不要说这题多水之类的--我只是想记一下kosaraju这种屌炸天的dfs序延伸算法(说不定能加到我的ygylca里面)*/ 题意神马的都不说了,好吧,就是给你个图,n个点,然后n行每行都描述该点的出边,图建完了,然后缩点,然后问多少个点没有入度,再问需要加几条边可以让图变强联通图. 强联通图:图中任意两点之间都能互相到达(前提得是有向图你懂的,无向图就有点乱了,根本不要算法了,暴搜就好了) 强联通分量:同强联通图,不过是图中一部分. 缩点,把一个分量视为一个点,缩起来(一般不缩,都是记录每个

hihoCoder#1185 : 连通性&#183;三 tarjan求强联通分量 缩点 dfs/拓扑排序求路径和最大值

题目链接: http://hihocoder.com/problemset/problem/1185# 题意: n个点,每个点有一个权值,m条有向边,从1出发,每走到一个点, 就吃掉这个点的草,当没有可以到达的草场或是能够到达的草场都已经被吃光了之后就要返回到1了.求最多可以吃掉多少草. 思路: 提示里面讲的挺好的 如果草场是一个强连通图,那么我们只要走到任意一点,就可以把其他所有的草场都走一遍,并且可以选择任意一个点作为终点.所以把强联通块缩成一个点 因为一个强连通块会被缩成一个点,那么我们可

【强联通分量缩点】【最长路】【spfa】CH Round #59 - OrzCC杯NOIP模拟赛day1 队爷的讲学计划

10分算法:对于城市网络为一条单向链的数据, 20分算法:对于n<=20的数据,暴力搜出所有的可能路径. 结合以上可以得到30分. 60分算法:分析题意可得使者会带着去的城市也就是这个城市所在强联通分量的其他城市,这个过程的代价也就是这个强联通分量的城市数-1,且他可以选择任何一个其中的城市离开这个强联通分量.于是我们求出所有强联通分量,记录下每一个包含的城市数,然后缩点.接下来再用dfs,由于数据是构造的,只能得到60分. 100分算法:在缩点之后,这个图变成了一个有向无环图,我们将一条边连向

【最小割】【Dinic】【强联通分量缩点】bzoj1797 [Ahoi2009]Mincut 最小割

结论: 满足条件一:当一条边的起点和终点不在 残量网络的 一个强联通分量中.且满流. 满足条件二:当一条边的起点和终点分别在 S 和 T 的强联通分量中.且满流.. 网上题解很多的. 1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 #define IN

【强联通分量缩点】【搜索】bzoj2208 [Jsoi2010]连通数

两次dfs缩点,然后n次dfs暴搜. 1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 using namespace std; 5 #define N 2001 6 vector<int>G[N],rG[N],vs,G2[N]; 7 typedef vector<int>::iterator ITER; 8 char s[N+1][N+1]; 9 int cmp[N],sum

【强联通分量缩点】【最短路】【spfa】bzoj1179 [Apio2009]Atm

缩点后转化成 DAG图上的单源最长路问题.spfa/dp随便. 1 #include<cstdio> 2 #include<queue> 3 #include<algorithm> 4 #include<vector> 5 #include<cstring> 6 using namespace std; 7 int cmp[500001],sum,n,m,Us[500001],Vs[500001],t,w[500001],sta,k,ans,di

Light OJ 1034 - Hit the Light Switches(强联通分量)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1034 题目大意:有n盏灯,有m个关系, 关系a,b表示如果a灯开关打开那么b灯也会亮起来, 现在求至少需要打开多少开关使所有灯都亮. 题目思路:先由强联通分量缩点, 得到DAG图, 然后根据DAG图,求出有多少入度为0的点, 即为所求. 代码如下: #include<bits/stdc++.h> using namespace std; const int N = 1000

codevs 2822 爱在心中 tarjan(强联通分量)

2822 爱在心中 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description “每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动.爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our Home.” 在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况).爱是具有传递性的,即如果A爱B,B爱C,则A也爱C.如果有这样一部分人,他们彼此都相爱,则他们就超越了一