• 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; 
    }

  • 相关阅读:
    软考解析:2014年上半年下午试题
    软考解析:2014年下半年下午试题
    软考解析:2015年下半年下午试卷
    软考解析:2015年上半年下午试卷
    怎样完善和推广自己的理论模型?
    怎样完善和推广自己的理论模型?
    Android开发——常见的内存泄漏以及解决方案(一)
    聊聊Android5.0中的水波纹效果
    JVM——自定义类加载器
    JVM——Java类加载机制总结
  • 原文地址:https://www.cnblogs.com/anhuizhiye/p/3933139.html
Copyright © 2020-2023  润新知