Problem B: The Largest Clique
Given a directed graph G, consider the following transformation. First, create a new graphT(G) to have the same vertex set as G. Create a directed edge betweentwo vertices u and v in T(G) if and only if there is a pathbetween u and v in G that follows the directed edges only in the forwarddirection. 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 thatfor any two vertices u and v in U, there is a directededge 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 integersn and m, where 0 ≤ n ≤ 1000 is the number ofvertices of Gand 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 vbetween 1 and n which definea 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
题目大意:
给一张n个结点、m条边的有向图G,求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足:要么u可以到达v,要么v可以到达u(u和v相互可达也行)。(0 <= n <= 1000,0 <= m <= 50000)结点编号1~n。
题目分析:
很明显的强连通缩点+DAG最长路。不难发现在最优方案中,同一个强连通分量中的点要么都选,要么不选。把强连通分量缩点后得到SCC图,让SCC图的结点的权值等于它代表的强连通分量的结点数,则题目转化成为求SCC图上点权最大的路径。由于SCC是一个DAG图,所以用DAG上的动态规划求解即可。
代码如下:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std ;
#define clear( A , X ) memset ( A , X , sizeof A )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define FF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
const int maxN = 1005 ;
const int maxS = 20005 ;
const int maxQ = 20005 ;
const int maxE = 1000005 ;
const int oo = 0x3f3f3f3f ;
struct Edge {
int v , n ;
Edge () {}
Edge ( int var , int next ) : v(var) , n(next) {}
} ;
struct DAG_DP {
Edge edge[maxE] ;
int adj[maxN] , cntE ;
int Q[maxQ] , head , tail ;
int in[maxN] ;
int d[maxN] ;
int dis[maxN] ;
void Addedge ( int u , int v ) {
edge[cntE] = Edge ( v , adj[u] ) ;
adj[u] = cntE ++ ;
}
void Init () {
cntE = 0 ;
head = tail = 0 ;
clear ( d , 0 ) ;
clear ( in , 0 ) ;
clear ( dis , 0 ) ;
clear ( adj , -1 ) ;
}
void DEBUG ( int n ) {
FF ( i , 1 , n )
printf ( "d[%d] = %d\n" , i , d[i] ) ;
FF ( i , 1 , n )
printf ( "in[%d] = %d\n" , i , in[i] ) ;
}
void DP ( int n ) {
int ans = 0 ;
FF ( i , 1 , n ) {
if ( !in[i] ) {
Q[tail ++] = i ;
dis[i] = d[i] ;
if ( ans < dis[i] )
ans = dis[i] ;
}
}
//DEBUG ( n ) ;
while ( head != tail ) {
int u = Q[head ++] ;
for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
int v = edge[i].v ;
if ( dis[v] < dis[u] + d[v] ) {
dis[v] = dis[u] + d[v] ;
if ( ans < dis[v] )
ans = dis[v] ;
}
if ( 0 == ( -- in[v] ) )
Q[tail ++] = v ;
}
}
printf ( "%d\n" , ans ) ;
}
} ;
struct SCC {
Edge edge[maxE] ;
DAG_DP DAG ;
int adj[maxN] , cntE ;
int scc[maxN] , Dfn[maxN] , Low[maxN] ;
int dfs_clock , scc_cnt ;
int S[maxS] , ins[maxN] , top ;
void Addedge ( int u , int v ) {
edge[cntE] = Edge ( v , adj[u] ) ;
adj[u] = cntE ++ ;
}
void Init () {
top = 0 ;
cntE = 0 ;
scc_cnt = 0 ;
dfs_clock = 0 ;
clear ( Dfn , 0 ) ;
clear ( ins , 0 ) ;
clear ( adj , -1 ) ;
}
void Tarjan ( int u ) {
Dfn[u] = Low[u] = ++ dfs_clock ;
ins[u] = 1 ;
S[top ++] = u ;
for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
int v = edge[i].v ;
if ( !Dfn[v] ) {
Tarjan ( v ) ;
Low[u] = min ( Low[u] , Low[v] ) ;
}
else if ( ins[v] ) {
Low[u] = min ( Low[u] , Dfn[v] ) ;
}
}
if ( Low[u] == Dfn[u] ) {
++ scc_cnt ;
while ( 1 ) {
int v = S[-- top] ;
ins[v] = 0 ;
scc[v] = scc_cnt ;
if ( v == u ) break ;
}
}
}
void Find_SCC ( int n ) {
FF ( i , 1 , n )
if ( !Dfn[i] )
Tarjan ( i ) ;
}
void Graph_Build ( int n ) {
DAG.Init () ;
FF ( i , 1 , n )
++ DAG.d[scc[i]] ;
FF ( u , 1 , n ) {
for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
int v = edge[i].v ;
if ( scc[u] != scc[v] ) {
DAG.Addedge ( scc[u] , scc[v] ) ;
++ DAG.in[scc[v]] ;
}
}
}
}
} ;
SCC scc ;
void work () {
int n , m , u , v ;
scc.Init () ;
scanf ( "%d%d" , &n , &m ) ;
REP ( i , m ) {
scanf ( "%d%d" , &u , &v ) ;
scc.Addedge ( u , v ) ;
}
scc.Find_SCC ( n ) ;
if ( scc.scc_cnt == 1 ) {
printf ( "%d\n" , n ) ;
return ;
}
scc.Graph_Build ( n ) ;
scc.DAG.DP ( n ) ;
}
int main () {
int T ;
scanf ( "%d" , &T ) ;
while ( T -- )
work () ;
return 0 ;
}