zoukankan      html  css  js  c++  java
  • ZOJ 3795 Grouping

    大致题意是给n个人和m组关系,每组关系都是两个人s和t,表示s年龄不小于t的年龄,然后让你把这n个人分组,使得任何一个组里面的任意两人都不能直接或间接的得出这两个人的年龄大小关系。

    思路:根据给出的关系建图,问题转化为求图里面的一个最长链。考虑简单情形:图里面没有回路,那么直接dp+记忆化搜索就OK了,len[u] = max(len[u],len[v] + 1),(u,v相邻)。若有回路,那么利用tarjan进行缩点,把一个强连通分量里面的所有点缩成一个点,该点的权重就是分量里面点的个数,仍利用上述方法求解即可 len[u] = max(len[u],len[v] + w[u])

    #include<cstdio>
    #include<string>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std; 
    const int MAXN = 100010; 
    int ind, top, cnt;  
    int vis[MAXN], len[MAXN], head[MAXN], shead[MAXN]; 
    int dfn[MAXN], low[MAXN], st[MAXN], num[MAXN], w[MAXN]; 
    struct Edge{
        int to, next; 
    }; 
    Edge edge[3*MAXN], sedge[3*MAXN]; 
    void addEdge(int u, int v, int k){
        edge[k].to = v; 
        edge[k].next = head[u]; 
        head[u] = k; 
    }
    void saddEdge(int u, int v, int k){
        sedge[k].to = v; 
        sedge[k].next = shead[u]; 
        shead[u] = k; 
    }
    void tarjan(int u){
        dfn[u] = low[u] = ++ind; 
        vis[u] = 1, st[++top] = u; 
        for(int i = head[u];  ~i; i = edge[i].next){
            int v = edge[i].to;
            if(!dfn[v]){
                tarjan(v); 
                low[u] = min(low[u], low[v]); 
            }else if(vis[v]) low[u] = min(low[u], dfn[v]); 
        }
        int tmp; 
        if(low[u] == dfn[u]){
            do{
                tmp = st[top--];
                num[tmp] = cnt; 
                vis[tmp] = 0; 
            }while(tmp != u); 
            cnt ++; 
        }
    }
    int dfs(int u){
        vis[u] = 1, len[u] = w[u]; 
        for(int i = shead[u]; ~i; i = sedge[i].next){
            int v = sedge[i].to; 
            if(vis[v]) len[u] = max(len[u], len[v] + w[u]); 
            else len[u] = max(len[u], dfs(v) + w[u]); 
        }
        return len[u];
    }
    int solve(int n){
        int k = 1; 
        ind = top = 0;
        cnt = 1; 
        memset(w, 0, sizeof(w)); 
        memset(dfn, 0, sizeof(dfn)); 
        memset(vis, 0, sizeof(vis)); 
        for(int i = 1; i <= n; i ++)
            if(!dfn[i]) tarjan(i); 
        memset(shead, -1, sizeof(shead)); 
        for(int i = 1; i <= n; i ++){
            w[num[i]] ++; 
            for(int j = head[i]; ~j; j = edge[j].next){
                int u = edge[j].to;
                if(num[i] != num[u]) saddEdge(num[i], num[u], k++); 
            }
        }
        int ans = 1; 
        memset(vis, 0, sizeof(vis)); 
        for(int i = 1; i < cnt; i ++){
            if(!vis[i]) dfs(i); 
            ans = max(ans, len[i]); 
        }
        return ans; 
    }
    int main(){
        int n, m; 
    #ifndef ONLINE_JUDGE
        freopen("in.cpp", "r", stdin); 
    #endif
        while(~scanf("%d%d", &n, &m)){
            int u, v; 
            memset(head, -1, sizeof(head)); 
            for(int i = 1; i <= m; i ++){
                scanf("%d%d", &u, &v); 
                addEdge(v, u, i); 
            }
            printf("%d
    ", solve(n)); 
        }
        return 0; 
    }

  • 相关阅读:
    自动机实验
    11.11评论
    语法分析
    201406114257 张俊毅 词法分析 修改完
    201406114257 张俊毅 词法分析
    做汉堡
    复利计算5.0-结队
    《构建之法》第4章的感悟
    复利计算4.0单元测试
    实验一 命令解释程序的编写
  • 原文地址:https://www.cnblogs.com/anhuizhiye/p/3933139.html
Copyright © 2011-2022 走看看