缩点模板 tarjan+SPFA 40pts 求调
查看原帖
缩点模板 tarjan+SPFA 40pts 求调
409774
Maysoul楼主2023/7/4 17:21

思路:用tarjan进行缩点处理,在缩点后的图上依次跑SPFA求最短路径

//2023/7/4
//别着急,先通读一遍题目
//别忘了开long long
//写完先看一遍怎么降复杂度
//要么开全局变量要么给定初值
//想想看,有什么情况需要特判
//看看数组开的够不够大
//std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int INF=0x3f3f3f3f;
int num,ans;
struct link{
	int from,to,w,next;
}edge[2*MAXN];
struct star{
	int from,to,w,next;
}bian[2*MAXN];
int head[MAXN],dfn[MAXN],low[MAXN],id[MAXN],tot[MAXN],staing[MAXN],du[MAXN];
int point[MAXN],dis[MAXN],vis[MAXN],tou[MAXN];
int escnt,tim,root,ancnt;
stack<int> stk;
void add_1(int u,int v)
{
	edge[++escnt].from=u;
	edge[escnt].to=v;
	edge[escnt].next=head[u];
	head[u]=escnt;
}
void add_2(int u,int v)
{
	bian[++ancnt].from=u;
	bian[ancnt].to=v;
	bian[ancnt].next=tou[u];
	tou[u]=ancnt;
}
void tarjan(int u)
{
	dfn[u]=low[u]=++tim;
	stk.push(u);
	staing[u]=1;
	for (int i=head[u];i!=-1;i=edge[i].next){
		int v=edge[i].to;
		if(dfn[v]==0){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(staing[u]){
			low[u]=min(low[u],dfn[v]);
		}
	}
	int k;
	if(low[u]==dfn[u]){
		++num;
		do{
			k=stk.top();
			stk.pop();
			staing[k]=0;
			id[k]=num;
			tot[num]+=point[k]; 
		}while(u!=k);
	}
}
int n,m,x,y;
int SPFA(int sid)
{
	int sum=0;
	for (int i=1;i<=n;i++)
	{
		dis[i]=-INF;
	}
	queue<int> que;
	memset(vis,false,sizeof(vis));
	dis[sid]=0;
	vis[sid]=1;
	que.push(sid);
	while(!que.empty())
	{
		int cp=que.front();
		que.pop();
		vis[cp]=false;
		sum=max(sum,dis[cp]+tot[cp]);
		for (int i=tou[cp];i!=-1;i=bian[i].next)
		{
			int eto=bian[i].to;
			int ew=bian[i].w;
			if(dis[eto]<dis[cp]+ew)
			{
				dis[eto]=dis[cp]+ew;
				if(!vis[eto])
				{
					que.push(eto);
					vis[eto]=true;
				}
			}
		}
	}
	return sum;
}
int main()
{
	memset(head,-1,sizeof(head));
	memset(tou,-1,sizeof(tou));
	cin>>n>>m;
	for (int i=1;i<=n;i++)	cin>>point[i];
	for (int i=1;i<=m;i++){
		cin>>x>>y;
		add_1(x,y);
	}
	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!=-1;j=edge[j].next){
			int v=edge[j].to;
			if(id[j]==id[v]) continue;
			add_2(id[j],id[v]);
		}
	}
	for (int i=1;i<=num;i++){
		ans=max(SPFA(i),ans);
	}
	cout<<ans<<endl;
	return 0;
}

2023/7/4 17:21
加载中...