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).
1
5 5
1 2
2 3
3 1
4 1
5 2
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 ; }