The Largest Clique
Time Limit: 3000MS 64bit IO Format: %lld & %llu
Description
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.
Input
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.
Output
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
Sample Output
4
求最大点集使得集合中任意两个点u v 满足 u能到v || v能到u 。。。
那么在同一个SCC中的点要么全取(对答案贡献更大)要么全部不去,那么缩点之后拓扑排序进行dp就可以了。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=2005;
struct Edge
{
int to,next;
}edge[maxn*maxn];
int head[maxn];
int maxedge;
inline void addedge(int u,int v)
{
edge[++maxedge]=(Edge){v,head[u]};
head[u]=maxedge;
}
int n,m;
void init()
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
maxedge=-1;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
}
}
int dfs_clock;
int dfn[maxn],sccno[maxn];
bool insta[maxn];
stack <int> sta;
struct Scc
{
int cnt;
vector <int> a[maxn];
void clear()
{
cnt=0;
for(int i=1;i<=n+1;i++) a[i].clear();
}
void add(int tmp) { a[cnt].push_back(tmp); sccno[tmp]=cnt; }
}scc;
int dfs(int u)
{
int lowu=dfn[u]=++dfs_clock;
sta.push(u);insta[u]=true;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v])
{
int lowv=dfs(v);
lowu=min(lowu,lowv);
}
else if(insta[v]) lowu=min(lowu,dfn[v]);
}
if(lowu>=dfn[u])
{
scc.cnt++;
int tmp;
do
{
tmp=sta.top();sta.pop();insta[tmp]=false;
scc.add(tmp);
}while(tmp^u);
}
return lowu;
}
void tarjan()
{
memset(dfn,0,sizeof(dfn));
memset(sccno,0,sizeof(sccno));
dfs_clock=0;scc.clear();//!!!!!significant to clear the scc!!!!!!
for(int i=1;i<=n;i++)
if(!dfn[i]) dfs(i);
}
Edge edge2[maxn*maxn];
int head2[maxn];
int maxedge2;
inline void addedge2(int u,int v)
{
edge2[++maxedge2]=(Edge){v,head2[u]};
head2[u]=maxedge2;
}
int in[maxn],val[maxn];//,out[maxn]
stack <int> topo;
int topos[maxn],dp[maxn];
void toposort()
{
for(int k=1;k<=scc.cnt;k++)
if(!in[k]) topo.push(k);
int pos=0;//up to scc.cnt
while(!topo.empty())
{
int tmp=topo.top();topo.pop();
topos[++pos]=tmp;
for(int i=head2[tmp];~i;i=edge2[i].next)
{
int v=edge2[i].to;
if(--in[v]==0) topo.push(v);
}
}
}
int dynamic()
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=scc.cnt;i++) dp[topos[i]]=val[topos[i]];//last WA: dp[i]=val[yopos[i]]
for(int i=1;i<=scc.cnt;i++)//i for sub in dp, dp indicates the sccno
{
for(int j=head2[topos[i]];~j;j=edge2[j].next)
{
int v=edge2[j].to;//the sccno
dp[v]=max(dp[v],dp[topos[i]]+val[v]);//last WA: dp[i] && dp[topos[v]]!!
}
}
return *max_element(dp+1,dp+scc.cnt+1);
}
void work()
{
tarjan();
memset(head2,-1,sizeof(head2));
memset(in,0,sizeof(in));
//memset(out,0,sizeof(out));
maxedge2=-1;
for(int i=1;i<=n;i++)
for(int j=head[i];~j;j=edge[j].next)
if(sccno[i]^sccno[edge[j].to]) in[sccno[edge[j].to]]++,addedge2(sccno[i],sccno[edge[j].to]);//,out[sccno[i]]++
for(int k=1;k<=scc.cnt;k++)
val[k]=scc.a[k].size();
toposort();
printf("%d\n",dynamic());
}
int main()
{
#ifdef Local
freopen("clique.in","r",stdin);
freopen("clique.out","w",stdout);
#endif
int cas;
scanf("%d",&cas);
while(cas--)
{
init();
work();
}
return 0;
}