【强连通分量缩点】【记忆化搜索】bzoj1589 [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果

缩成DAG

f(i)表示以i为起点的最长路

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define N 100001
int n,To[N],mem[N];
vector<int>vs;
int v[N],first[N],next[N],en;
void AddEdge(int U,int V)
{
	v[++en]=V;
	next[en]=first[U];
	first[U]=en;
}
int v2[N],firs2[N],nex2[N],e2;
void AddEdg2(int U,int V)
{
	v2[++e2]=V;
	nex2[e2]=firs2[U];
	firs2[U]=e2;
}
int w[N],cmp[N],tot;
bool vis[N];
void dfs(int U)
{
	vis[U]=1;
	for(int i=first[U];i;i=next[i])
	  if(!vis[v[i]])
	    dfs(v[i]);
	vs.push_back(U);
}
void df2(int U)
{
	cmp[U]=tot;
	++w[tot];
	for(int i=firs2[U];i;i=nex2[i])
	  if(!cmp[v2[i]])
	    df2(v2[i]);
}
void scc()
{
	for(int i=1;i<=n;++i)
	  if(!vis[i])
	    dfs(i);
	vector<int>::iterator it=vs.end(); --it;
	while(1)
	  {
	  	if(!cmp[*it])
	  	  {
	  	  	++tot;
	  	  	df2(*it);
	  	  }
	  	if(it==vs.begin())
	  	  break;
	  	--it;
	  }
}
int f(int U)
{
	if(mem[U]) return mem[U];
	mem[U]=w[U];
	for(int i=first[U];i;i=next[i])
	  mem[U]=max(mem[U],f(v[i])+w[U]);
	return mem[U];
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	  {
	  	scanf("%d",&To[i]);
	  	AddEdge(i,To[i]);
	  	AddEdg2(To[i],i);
	  }
	scc();
	memset(first,0,sizeof(first));
	memset(next,0,sizeof(next));
	memset(v,0,sizeof(v));
	en=0;
	for(int i=1;i<=n;++i)
	  if(cmp[i]!=cmp[To[i]])
	    AddEdge(cmp[i],cmp[To[i]]);
	for(int i=1;i<=n;++i)
	  printf("%d
",f(cmp[i]));
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/4372260.html