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<<"\tnumber:"<<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\n", ans);
    }
    return 0;
}

 

posted @ 2013-09-06 22:24  Ramanujan  阅读(247)  评论(0编辑  收藏  举报