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
-----------------------------------------
缩点,求最大团
-----------------------------------------
#include <iostream> #include <vector> #include <stack> #include <cstring> #include <cstdio> using namespace std; const int maxn=1111; const int INF=1e8; void dfs(int u);//搜索求强连通 void find_scc(int n);//求强连通 void tops(int n);//拓扑排序 int w[maxn];//点权 vector<int>a[maxn];//DAG图 vector<int>G[maxn];//原图 int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;//Tarjan stack<int> S;//Tarjan int indegree[maxn];//入度 int ans; bool hash[maxn][maxn]; //-----Tarjan------ void dfs(int u) { pre[u]=lowlink[u]=++dfs_clock; S.push(u); int len=G[u].size(); for (int i=0;i<len;i++) { int v=G[u][i]; if (!pre[v]) { dfs(v); lowlink[u]=min( lowlink[u], lowlink[v] ); } else if (!sccno[v]) { lowlink[u]=min( lowlink[u], pre[v] ); } } if (lowlink[u]==pre[u]) { scc_cnt++; while (true) { int x=S.top(); S.pop(); sccno[x]=scc_cnt; w[scc_cnt]++; if (x==u) break; } } } void find_scc(int n) { dfs_clock=scc_cnt=0; memset(sccno,0,sizeof(sccno)); memset(pre,0,sizeof(pre)); memset(w,0,sizeof(w)); while (!S.empty()) S.pop(); for (int i=1;i<=n;i++) { if (!pre[i]) dfs(i); } } int f[maxn]; int DP(int u) { int ret=0; int sz=a[u].size(); for (int i=0;i<sz;i++) { int v=a[u][i]; ret=max(ret,DP(v)); } f[u]=ret+w[u]; return f[u]; } //----------------- int main() { int T; int n,m; scanf("%d",&T); while (T--) { //init() memset(indegree,0,sizeof(indegree)); memset(hash,0,sizeof(hash)); memset(f,0,sizeof(f)); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { G[i].clear(); a[i].clear(); } for (int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); } //强连通 find_scc(n); //缩点 for (int i=1;i<=n;i++) { int sz=G[i].size(); for (int j=0;j<sz;j++) { int v=G[i][j]; if (sccno[i]!=sccno[v]&&!hash[sccno[i]][sccno[v]]) { a[sccno[i]].push_back(sccno[v]); hash[sccno[i]][sccno[v]]=true; indegree[sccno[v]]++; } } } ans=0; for (int i=1;i<=n;i++) { if (indegree[i]==0) { ans=max(ans,DP(i)); } } //输出 printf("%d\n",ans); } return 0; }