一道做起来很舒服的题

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 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
Hint

set1= {1}, set2= {2, 3}, set3= {4} 


题意:有n个人,m个关系(a b),代表a会和b比较,且关系可以传递,问这么把这些人分到不同的群组里面,使得每个群组里面的人都不能比较,差不多是这个意思了。


第一感觉是强联通,得到一个有向无环图,找到最大的强联通分量,然后想想不太对,如果一个链够长,好像也可以,然后改了改,改成缩点之后,跑最长链,其中强联通分量的节点个数是该节点的权重,用个记忆话搜索,从重建的图中入度为0的点开始搜,找个最大值。


#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int maxm = 300010;
const int maxn = 100010;

typedef struct Edge {
    int to,next;
};

Edge edge[maxm];
int head[maxn],cnt;
int stack[maxn],instack[maxn],dfn[maxn],low[maxn],col[maxn];
int sec,top,ttime;
int ans_max,ans_len;
int deg[maxn],sum[maxn];

Edge redge[maxm];
int rhead[maxn],rcnt;
int mark[maxn];

int queue[maxn];

void Add(int from,int to) {
    edge[cnt].to = to;
    edge[cnt].next = head[from];
    head[from] = cnt ++;
}

void rAdd(int from,int to) {
    redge[rcnt].to = to;
    redge[rcnt].next = rhead[from];
    rhead[from] = rcnt ++;
}

void Tarjan(int s) {
    stack[top ++] = s;
    instack[s] = 1;
    dfn[s] = low[s] = ttime ++;
    for(int i = head[s]; i + 1; i = edge[i].next) {
        int to = edge[i].to;
        if(dfn[to] == -1) {
            Tarjan(to);
            low[s] = min(low[s],low[to]);
        }
        else if(instack[to]) {
            low[s] = min(low[s],dfn[to]);
        }
    }
    if(low[s] == dfn[s]) {
        int x;
        int t = 0;
        do {
            x = stack[-- top];
            instack[x] = 0;
            col[x] = sec;
            t ++;
            //printf("%d\n",x);
        }while(s != x);
        //printf("*****\n");
        sum[sec] = t;
        sec ++;
        ans_max = max(ans_max,t);
    }
}

void rebuild(int N) {
    memset(rhead,-1,sizeof(rhead));
    rcnt = 0;
    for(int i = 1; i <= N; i ++) {
        int from = i;
        for(int j = head[i]; j + 1; j = edge[j].next) {
            int to = edge[j].to;
            if(col[from] != col[to]) {
                rAdd(col[from],col[to]);
                //printf("%d -> %d\n",col[from],col[to]);
            }
        }
    }
}

int dfs(int s) {
    int ans = 0;
    //printf("s = %d\n",s);
    for(int i = rhead[s]; i + 1; i = redge[i].next) {
        int to = redge[i].to;
        if(mark[to]) {
            ans = max(ans,mark[to]);
            continue;
        }
        dfs(to);
        ans = max(ans,mark[to]);
    }
    mark[s] = ans + sum[s];
    return mark[s];
}

int main() {
    int N,M;
    while(~scanf("%d%d",&N,&M)) {
        memset(head,-1,sizeof(head));
        memset(dfn,-1,sizeof(dfn));
        memset(instack,0,sizeof(instack));
        memset(sum,0,sizeof(sum));
        top = cnt = sec = ttime = 0;
        for(int i = 0; i < M; i ++) {
            int a,b;
            scanf("%d%d",&a,&b);
            Add(a,b);
        }
        ans_max = 0;
        for(int i = 1; i <= N; i ++) {
            if(dfn[i] == -1) {
                Tarjan(i);
            }
        }
        //printf("ans_max = %d\n",ans_max);
        //printf("sec = %d\n",sec);
        rebuild(N);
        memset(deg,0,sizeof(deg));
        for(int i = 0; i < sec; i ++) {
            for(int j = rhead[i]; j + 1; j = redge[j].next) {
                int to = redge[j].to;
                deg[to] ++;
            }
        }
        ans_len = 0;
        for(int i = 0; i < sec; i ++) {
            if(deg[i] == 0) {
                memset(mark,0,sizeof(mark));
                int x = dfs(i);
                ans_len = max(x,ans_len);
            }
        }
        //printf("len = %d\n",ans_len);
        printf("%d\n",max(ans_len,ans_max));
    }
    return 0;
}

做起来很舒服,没有什么难点,把简单的东西组合起来的题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值