Tarjan缩点+分层图+spfa最长路【洛谷P3119】

传送门:https://www.luogu.org/problemnew/show/P3119

这个题目一眼看上去,有环,我们就直接tarjan缩点。

但是有一条边可以逆着走,很显然的思路就是枚举每条边,记录一个最大值。(我不会写枚举边的暴力)

所以我们来介绍一下另外一种思路,建分层图。

现在我们在缩点之后的DAG上操作。

我们在DAG上建图的时候,用下图的方式建:

DAG结点为1,2,3,多加出来的点为4,5,6,我们就把2连到4,3连到5,这样,2到4就相当于2到1,也就是1到2的反边。

具体怎么建的,就是add(from,to),add(to,from+N),add(from+N,to+N);

这样,我们就把分层图给建好啦。

哦对了,权值别忘记更新了,这个题目是点权,没关系,把他当成边权就可以了。

然后在分层图上从1跑spfa最长路,因为最后必须回到1,所以结果就是dis[color[1]+N],因为1号结点对应的是1+N结点。

下面是大家喜闻乐见的代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+7;
int low[maxn],dfn[maxn];
vector<int> E[maxn];
vector<int> G[maxn*2];
int color[maxn],sum[maxn*2]; 
int n,m;
int cnt,col;
stack<int> s;
int ins[maxn];
int inq[maxn];
int dis[maxn];
void tarjan(int x)
{
	low[x] = dfn[x] = ++cnt;
	s.push(x);
	ins[x] = 1;
	for(int i=0;i<E[x].size();i++)
	{
		int v = E[x][i];
		if(!dfn[v])
		{
			tarjan(v);
			low[x] = min(low[x],low[v]);
		}
		else if(ins[v])
		{
			low[x] = min(low[x],dfn[v]);
		}
	}
	if(low[x]==dfn[x])
	{
		++col;
		while(true)
		{
			int tmp = s.top();
			s.pop();
			sum[color[tmp]=col]++;
			ins[tmp] = 0;
			if(tmp==x) break;
		}
	}
}
void spfa(int s)
{
	queue<int> q;
	q.push(s);
	inq[s] = 1;
	while(!q.empty())
	{
		int now = q.front();
		q.pop();
		inq[now] = 0;
		for(int i=0;i<G[now].size();i++)
		{
			int v = G[now][i];
			if(dis[v]<dis[now]+sum[v])
			{
				dis[v] = dis[now]+sum[v];
				if(!inq[v])
				{
					inq[v] = 1;
					q.push(v);
				}
			} 
		}
	}
}
int main()
{
	cin>>n>>m;
	int x,y;
	for(int i=0;i<m;i++)
	{
		cin>>x>>y;
		E[x].push_back(y);
	}
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i]) tarjan(i);
	}
	if(col==1)
	{
		cout<<sum[color[1]]<<endl;
		return 0;
	}
	for(int i=1;i<=col;i++)
	{
		sum[i+col] = sum[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<E[i].size();j++)
		{
			int v = E[i][j];
			if(color[i]!=color[v])
			{
				G[color[i]].push_back(color[v]);
				G[color[v]].push_back(color[i]+col);
				G[color[i]+col].push_back(color[v]+col);
			}
		}
	}
	spfa(color[1]);
	cout<<dis[color[1]+col]<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/84315804