tarjan缩点求调
查看原帖
tarjan缩点求调
229957
Wu_while楼主2021/10/11 20:29
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>
#define MAXN 10010
#define MAXM 100010
using namespace std;
struct Edge
{
	int from;
	int to;
	int nxt;
}
edge[MAXM];
int head[MAXN],size;
struct Edge_
{
	int to;
	int nxt;
}
edge_[MAXM];
int head_[MAXN],size_;
void add(int from,int to)
{
	edge[++size].nxt=head[from];
	edge[size].from=from;
	edge[size].to=to;
	head[from]=size;
}
void add_(int from,int to)
{
	edge_[++size_].nxt=head_[from];
	edge_[size_].nxt=to;
	head_[from]=size_;
}
void init()
{
	memset(edge,-1,sizeof(edge));
	memset(head,-1,sizeof(head));
	memset(edge_,-1,sizeof(edge_));
	memset(head_,-1,sizeof(head_));
}
int n,m;
int a[MAXN];
int u,v;
int times;
int dfn[MAXN],low[MAXN];
bool vis[MAXN];
stack<int> sta;
int scc[MAXN],tot;
int dis[MAXN];
int in[MAXN];
void tarjan(int x)
{
	dfn[x]=low[x]=++times;
	vis[x]=1;
	sta.push(x);
	for(int i=head[x];~i;i=edge[i].nxt)
	{
		if(!dfn[edge[i].to])
		{
			tarjan(edge[i].to);
			low[x]=min(low[x],low[edge[i].to]);
		}
		else if(vis[edge[i].to])
			low[x]=min(low[x],low[edge[i].to]);
	}
	if(low[x]==dfn[x])
	{
		tot++;
		while(!sta.empty())
		{
			int t=sta.top();
			sta.pop();
			scc[t]=tot;
			dis[tot]+=a[t];
			vis[t]=0;
			if(t==x)
				break;
		}
	}
}
int top[MAXN],cnt;
void topsort()
{
	queue<int> q;
	for(int i=1;i<=tot;i++)
		if(in[i]==0)
			q.push(i);
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		top[++cnt]=u;
		for(int i=head_[u];~i;i=edge_[i].nxt)
		{
			in[edge_[i].to]--;
			if(in[edge_[i].to]==0)
				q.push(edge_[i].to);
		}
	}
}
int f[MAXN];
int ans;
int main()
{
	init();
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=m;i++)
	{
		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<=size;i++)
	{
		u=edge[i].from;
		v=edge[i].to;
		if(scc[u]==scc[v])
			continue;
		add_(scc[u],scc[v]);
		in[scc[v]]++;
	}
	topsort();
	for(int i=1;i<=tot;i++)
		f[i]=dis[i];
	for(int i=1;i<=tot;i++)
		for(int j=head_[i];~j;j=edge_[j].nxt)
			if(i!=edge_[j].to)
				f[edge_[j].to]=max(f[edge_[j].to],f[i]+dis[edge_[j].to]);
	for(int i=1;i<=tot;i++)
		ans=max(ans,f[i]);
	printf("%d",ans);
	return 0;
}

对于下面的数据一直在跑:

in:
10 20
970 369 910 889 470 106 658 659 916 964 
3 2
3 6
3 4
9 5
8 3
5 8
9 1
9 7
9 8
7 5
3 7
7 8
1 7
10 2
1 10
4 8
2 6
3 1
3 5
8 5


out:
6911
2021/10/11 20:29
加载中...