题目链接:UVA 11324
题意:给一个有向图,求一个结点数最大的结点集,使得该结点集中任意两点u和v满足:要么u可以到达v,要么v可以到达u,或是相互可达
建图,跑一遍强联通,然后用连通分量建新图,求一个新的DAG图上的最大权路径
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>
using namespace std;
const int maxn=1e5+7;
const int maxm=1e5+7;
struct Node
{
int to;
int next;
}edge[maxm<<1];
int cnt;
int idx;
int scc_cnt;
int head[maxn];
int dfn[maxn];
int low[maxn];
bool vis[maxn];
int num[maxn];
int belong[maxn];
int dp[maxn];
stack<int> sta;
vector<int> G[maxn];
void init()
{
cnt=idx=scc_cnt=0;
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,false,sizeof(vis));
memset(num,0,sizeof(num));
memset(belong,-1,sizeof(belong));
while(!sta.empty()) sta.pop();
for(int i=0;i<maxn;i++)
{
G[i].clear();
}
return;
}
void add(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
return;
}
void tarjan(int node)
{
dfn[node]=low[node]=++idx;
sta.push(node);
vis[node]=true;
for(int i=head[node];~i;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[node]=min(low[node],low[v]);
}
else if(vis[v])
{
low[node]=min(low[node],dfn[v]);
}
}
if(dfn[node]==low[node])
{
int v=-1;
++scc_cnt;
while(node!=v)
{
v=sta.top();
sta.pop();
belong[v]=scc_cnt;
num[scc_cnt]++;
vis[v]=false;
}
}
return;
}
int dfs(int node)
{
if(dp[node]!=-1) return dp[node];
dp[node]=num[node];
int len=G[node].size();
for(int i=0;i<len;i++)
{
int v=G[node][i];
dp[node]=max(dp[node],dfs(v)+num[node]);
}
return dp[node];
}
int main()
{
//freopen("in.txt","r",stdin);
int test;
scanf("%d",&test);
while(test--)
{
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
for(int i=1;i<=n;i++)
{
for(int j=head[i];~j;j=edge[j].next)
{
int v=edge[j].to;
if(belong[i]!=belong[v])
{
G[belong[i]].push_back(belong[v]);
}
}
}
int ans=0;
memset(dp,-1,sizeof(dp));
for(int i=1;i<=scc_cnt;i++)
{
ans=max(ans,dfs(i));
}
printf("%d\n",ans);
}
return 0;
}
/*
1
5 5
1 2
2 3
3 1
4 1
5 2
*/