UVA The Largest Clique (强联通分量 + 拓扑排序)

血红的双手。 提交于 2020-02-18 20:50:42

题目链接

题意:给你一张有向图,求一个节点数最大的节点集,使得该节点集中任意两个节点u,v。满足:要么u可达v,要么v可达u,要么互达。

思路:重新构造图,求出图中的所有scc,把同一个scc看做一个点,这样得到一张新的DAG,然后用拓扑排序求出DAG最长路即为答案。

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 2020;
int pre[maxn],low[maxn],scc[maxn],sz[maxn],d[maxn],dp[maxn];
int dfs_clock,scc_cnt;
vector<int>G[maxn],G1[maxn];
stack<int>s;
void dfs(int u)
{
	pre[u] = low[u] = ++dfs_clock;
	s.push(u);
	for(int i=0;i<G[u].size();i++)
	{
		int v = G[u][i];
		if(!pre[v])
		{
			dfs(v);
			low[u] = min(low[v],low[u]);
			
		}else if(!scc[v])low[u] = min(low[u],pre[v]);
	}
	if(low[u] == pre[u])
	{
		++scc_cnt;
		while(1)
		{
			int x = s.top();
			s.pop();
			scc[x] = scc_cnt;
			sz[scc_cnt]++;
			if(x == u)break;
		}
	}
}

void find_scc(int n)
{
	dfs_clock = scc_cnt = 0;
	memset(pre,0,sizeof(pre));
	memset(sz,0,sizeof(sz));
	memset(scc,0,sizeof(scc));
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=n;i++)
	if(!pre[i])dfs(i);
}

void topsort()
{
	queue<int>q;
	for(int i=1;i<=scc_cnt;i++)dp[i] = sz[i];
	for(int i=1;i<=scc_cnt;i++)if(!d[i])q.push(i);
	while(!q.empty())
	{
		int u = q.front();
		q.pop();
		for(int i=0;i<G1[u].size();i++)
		{
			int v = G1[u][i];
			dp[v] = max(dp[u] + sz[v],dp[v]);
			if(--d[v] == 0)q.push(v);
		}
	}
	int ans = *max_element(dp+1,dp+1+scc_cnt);
	printf("%d\n",ans);
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n+5;i++)G[i].clear(),G1[i].clear();
		memset(d,0,sizeof(d));
		for(int i=0;i<m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			G[u].pb(v);
		}
		find_scc(n);
		for(int u = 1;u<=n;u++)
		for(int i=0;i<G[u].size();i++)
		{
			int v = G[u][i];
			if(scc[v] == scc[u])continue;
			G1[scc[u]].pb(scc[v]);
			d[scc[v]]++;
		}
		topsort();
	}
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!