zoukankan      html  css  js  c++  java
  • uva 11324 The Largest Clique tarjan强连通分量

    Problem B: The Largest Clique

    Given a directed graph G, consider the following transformation. First, create a new graph T(G) to have the same vertex set as G. Create a directed edge between two vertices u and v in T(G) if and only if there is a path between u and v in G that follows the directed edges only in the forward direction. This graph T(G) is often called the transitive closure of G.

    We define a clique in a directed graph as a set of vertices U such that for any two vertices u and v in U, there is a directed edge either from u to v or from v to u (or both). The size of a clique is the number of vertices in the clique.

    The number of cases is given on the first line of input. Each test case describes a graph G. It begins with a line of two integers n and m, where 0 ≤ n ≤ 1000 is the number of vertices of G and 0 ≤ m ≤ 50,000 is the number of directed edges of G. The vertices of G are numbered from 1 to n. The following m lines contain two distinct integers u and v between 1 and n which define a directed edge from u to v in G.

    For each test case, output a single integer that is the size of the largest clique in T(G).

    Sample input

    1
    5 5
    1 2
    2 3
    3 1
    4 1
    5 2
    

    Output for sample input

    4
    

    Zachary Friggstad

    分析:

    因为强连通分量内点相互可达,所以可看成一个点考虑,即缩点。缩点后,原图变为有向无环图(DAG),则答案为求DAG上的一条路径,使得该路径上点权和最大,

    这里用bfs+拓扑顺序实现,这样可以避免重漏。另外,bfs时是重新建图的。

    1A代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<cstdlib>
    #include<queue>
    #include<algorithm>
    #include<stack>
    
    using namespace std;
    
    #define LL long long
    #define ULL unsigned long long
    #define UINT unsigned int
    #define MAX_INT 0x7fffffff
    #define MAX_LL 0x7fffffffffffffff
    #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
    #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
    
    #define MAXN 1111
    #define MAXM 111111
    
    vector<int> g[MAXN], ng[MAXN];
    stack<int> s;
    int dfn[MAXN], low[MAXN], in[MAXN];
    int cnt, tsp, id[MAXN];
    int num[MAXN], tn[MAXN];
    bool m[MAXN][MAXN], ins[MAXN];
    
    void tarjan(int u){
        dfn[u]=low[u]=++tsp;
        s.push(u);      ins[u]=true;
        int i, v, tl=g[u].size();
        for(i=0; i<tl; i++){
            v=g[u][i];
            if(!dfn[v]) tarjan(v), low[u]=MIN(low[u], low[v]);
            else if(ins[v]) low[u]=MIN(low[u], dfn[v]);             //ins避免横叉边
        }
        if(low[u]==dfn[u]){             //将强连通分量缩为一点
            cnt++;      num[cnt]=0;
       //     cout<<cnt<<endl;
            do{
                v=s.top();      s.pop();
         //       cout<<' '<<v;
                id[v]=cnt;
                ins[v]=false;
                num[cnt]++;
            }while(v!=u);
       //     cout<<"	number:"<<num[cnt]<<endl;
        }
    }
    
    queue<int> q;
    
    int topsort(){                          //DAG图,按拓扑序处理,求largest clique
        while(!q.empty()) q.pop();
        memset(tn, 0, sizeof(tn));
        for(int i=1; i<=cnt; i++) if(!in[i])
            q.push(i);
        while(!q.empty()){
            int u=q.front();    q.pop();
            int i=0, tl=ng[u].size();
            while(i<tl){
                int v=ng[u][i];         //num表该点含多少缩点前的点,tn表由拓扑序祖先可加入的最大点量
                tn[v]=MAX(tn[v], num[u]+tn[u]);
                in[v]--;                //删边
                if(!in[v]) q.push(v);   //可作为当前拓扑序首项
                i++;
            }
        }
    }
    
    int solve(int n){
        tsp=cnt=0;
        memset(id, 0, sizeof(id));
        memset(dfn, 0, sizeof(dfn));
        memset(ins, 0, sizeof(ins));
        for(int i=0; i<n; i++) if(!dfn[i])                  //求强连通,缩点
            tarjan(i);
        for(int i=1; i<=cnt; i++){
            ng[i].clear();
        }
        memset(m, 0, sizeof(m));
        memset(in, 0, sizeof(in));
        for(int i=0; i<n; i++){                             //重新建图,
            int u=id[i], tl=g[i].size();
            for(int j=0; j<tl; j++){
                int v=id[g[i][j]];
                if(u!=v && !m[u][v]){                   //避免重边
                    in[v]++;                            //计算入度
                    ng[u].push_back(v);
                    m[u][v]=true;
                }
            }
        }
        topsort();
        int ans=0;
    
        for(int i=1; i<=cnt; i++){
            ans=MAX(num[i]+tn[i], ans);
        }
        return ans;
    }
    
    int main(){
        //freopen("C:\Users\Administrator\Desktop\in.txt","r",stdin);
        int n, m, T;
        scanf(" %d",&T);
        while(T--){
            scanf(" %d %d", &n, &m);
            int i, u, v;
            for(i=0; i<n; i++) g[i].clear();
            for(i=0; i<m; i++){
                scanf(" %d %d", &u, &v); u--;   v--;
                g[u].push_back(v);
            }
            int ans=solve(n);
            printf("%d
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    mysql5.7初始化密码报错 ERROR 1820 (HY000): You must reset your password using ALTER USER statement before
    Http2和Http1.X的区别
    gitlab的搭建
    nginx的四层负载均衡和七层负载均衡的区别
    阿里云NAT网关配置
    docker-compose的最简单安装方式
    最快的安装 jdk8的方法
    centos6上搭建gitlab
    大牛讲解信号与系统以及数字信号处理
    【推荐图书】+ 基于Nios II的嵌入式SoPC系统设计与Verilog开发实例+C#入门经典等
  • 原文地址:https://www.cnblogs.com/ramanujan/p/3306447.html
Copyright © 2011-2022 走看看