UVa11324 The Largest Clique(强连通分量+DP)
题意:
看白书
要点:
求出强连通分量后缩成点,内部点数作为权,进行DAG的DP。
#include<iostream>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1010;
vector<int> g[maxn],map[maxn];
int dfn[maxn],lowlink[maxn],sccno[maxn],dfs_clock,cnt,n,m;
bool instack[maxn];
stack<int> s;
int val[maxn],dp[maxn];
void dfs(int u)
{
dfn[u]=lowlink[u]=++dfs_clock;
s.push(u);
instack[u]=true;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!dfn[v])
{
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if(instack[v])
{
lowlink[u]=min(lowlink[u],dfn[v]);
}
}
if(lowlink[u]==dfn[u])
{
cnt++;
for(;;)
{
int x=s.top();s.pop();
instack[x]=false;
sccno[x]=cnt;
if(x==u) break;
}
}
}
void Tarjan()
{
dfs_clock=cnt=0;
memset(instack,false,sizeof(instack));
memset(dfn,0,sizeof(dfn));
for(int i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
}
int d(int u)
{
if(dp[u])
return dp[u];
int ans=0;
for(int i=0;i<map[u].size();i++)
{
int v=map[u][i];
ans=max(ans,d(v));
}
return dp[u]=ans+val[u];
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<maxn;i++)
{
g[i].clear();
map[i].clear();
}
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
}
Tarjan();
memset(val,0,sizeof(val));
memset(dp,0,sizeof(dp));
//缩点
for(int u=1;u<=n;u++)
{
val[sccno[u]]++;
for(int j=0;j<g[u].size();j++)
{
int v=g[u][j];
if(sccno[u]!=sccno[v])
map[sccno[u]].push_back(sccno[v]);
}
}
int ans=0;//注意可能cnt为0,此时结果只能为0
for(int i=1;i<=cnt;i++)
ans=max(ans,d(i));
printf("%d\n",ans);
}
return 0;
}