Problem B: the largest clique
Given a Directed GraphG, Consider the following transformation. First, create a new GraphT (G)To have the same vertex setG. Create a directed edge between two verticesUAndVInT (G)If and only if there is a pathUAndVInGThat follows the directed edges only in the forward direction. This graphT (G)Is often calledTransitive ClosureOfG.
We defineCliqueIn a directed graph as a set of verticesUSuch that for any two verticesUAndVInU, There is a directed edge either fromUToVOr fromVToU(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 graphG. It begins with a line of two integersNAndM, Where 0 ≤N≤ 1000 is the number of verticesGAnd 0 ≤M≤ 50,000 is the number of directed edgesG. The verticesGAre numbered from 1N. The followingMLines contain two distinct integersUAndVBetween 1 andNWhich define a directed edge fromUToVInG.
For each test case, output a single integer that is the size of the largest clique inT (G).
Sample Input
15 51 22 33 14 15 2
Output for sample input
4
Strongly Connected Component shrinkage point + Dag DP
#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <string>#include <algorithm>#include <queue>#include <stack>using namespace std;const int maxn = 1000+10;const int maxm = 50000+10;struct edge{ int v,nxt;}e[maxm];int head[maxn];int nume;stack<int> S;int dfs_clk;int scc_no;int dfn[maxn],lown[maxn],sccno[maxn];int dp[maxn];int n,m;int num[maxn];vector<int> G[maxn];void init(){ while(!S.empty()) S.pop(); memset(head,0,sizeof head); memset(num,0,sizeof num); memset(dp,-1,sizeof dp); for(int i = 0; i <= n; i++){ G[i].clear(); } nume = 1; dfs_clk = 0; scc_no = 0; memset(dfn,0,sizeof dfn); memset(sccno,0,sizeof sccno);}void addedge(int u,int v){ e[++nume].nxt = head[u]; e[nume].v = v; head[u] = nume;}void dfs(int u){ dfn[u] = lown[u] = ++dfs_clk; S.push(u); for(int i = head[u]; i ; i = e[i].nxt){ int v = e[i].v; if(!dfn[v]){ dfs(v); lown[u] = min(lown[u],lown[v]); } else if(!sccno[v]){ lown[u] = min(lown[u],dfn[v]); } } if(lown[u] == dfn[u]){ scc_no++; while(true){ int x = S.top(); S.pop(); sccno[x] = scc_no; if(x==u) break; } }}void find_scc(){ for(int i = 1; i <= n; i++){ if(!dfn[i]) dfs(i); }}int dfs_dp(int x){ if(dp[x] != -1) return dp[x]; int ret = 0; for(int i = 0; i < G[x].size(); i++){ int d = G[x][i]; ret = max(ret,dfs_dp(d)+num[x]); } if(G[x].size()==0) ret = num[x]; return dp[x] = ret;}void solve(){ for(int i = 1; i <= n; i++){ int d = sccno[i]; num[d]++; for(int j = head[i]; j; j = e[j].nxt){ if(d!=sccno[e[j].v]) G[d].push_back(sccno[e[j].v]); } } int ret = 0; for(int i = 1; i <= scc_no; i++){ ret = max(ret,dfs_dp(i)); } printf("%d\n",ret);}int main(){ int ncase; cin >> ncase; while(ncase--){ scanf("%d%d",&n,&m); init(); while(m--){ int a,b; scanf("%d%d",&a,&b); addedge(a,b); } find_scc(); solve(); } return 0;}