dij + spfa + Tarjan

 Dij

#include<bits/stdc++.h>
using namespace std;
typedef pair<long long,int> P; //
const int N = 2e5+100;
int a[N],n,m,k,t;
int Head[N],Next[N*2],To[N*2],cnt = 0,val[N*2];
long long dis[N];
bool vis[N];
priority_queue<P,vector<P>, greater<P> > q; //小根堆。
void add(int u, int v, int w){
	++cnt;
	Next[cnt] =  Head[u];
	To[cnt] = v;
	val[cnt] = w;
	Head[u] = cnt;
}

void dij(){
	for (int i = 0; i <= n; ++i) dis[i] = 1e13;
	dis[1] = 0; q.push(P(0,1));
	while(!q.empty()){
		int u = q.top().second;  //找到dis 最小的起点。
		q.pop();
		if (vis[u]) continue;
		vis[u] = 1;   //这个起点已经更新过了。
		for (int i = Head[u]; i; i = Next[i]){ // 更新之后的点。
			int v = To[i];
			long long w = val[i];
			if (a[v] > t) w += 1ll*(a[v]-t)*(a[v]-t);  //这个是另外加的权值。
			if (dis[v] > dis[u] + w){
				dis[v] = dis[u] + w;
				q.push(P(dis[v],v));
			}
		}

	}
	return;
}

int main(){
	int x,y,z;
	scanf("%d%d%d",&n,&m,&k);
	for (int i = 1; i <= n; ++i) scanf("%d",&a[i]);
	for (int i = 0; i < m; ++i){
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z); add(y,x,z);
	}
	t = a[1] + k;  //判断能够达到最高的山高。
	dij();
	printf("%lld\n",dis[n]);

	return 0;
}

Tarjan + SPFA

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+1000;
int Head[N],Next[N],To[N],Val[N],cnt;
int n,m,S,p;
bool vis[N];
void add(int u, int v){
	Next[++cnt] = Head[u];
	Head[u] = cnt;
	To[cnt] = v;
}
void init(){
	int x,y;
	scanf("%d%d",&n,&m);
	for (int i = 0; i < m; ++i){
		scanf("%d%d",&x,&y);
		add(x,y);
	}
	for (int i = 1; i <= n; ++i)
		scanf("%d",&Val[i]);
	scanf("%d%d",&S,&p);
	for (int i = 0;i < p; ++i)
		scanf("%d",&x),vis[x] = 1;
}
stack<int>q;
int low[N],dfn[N],tim,scc[N],cont;
void Tarjan(int u){
	low[u] = dfn[u] = ++tim;
	q.push(u);
	for (int i = Head[u]; i; i = Next[i]){
		int v = To[i];
		if (!dfn[v]){
			Tarjan(v);
			low[u] = min(low[u],low[v]);
		} else if (!scc[v]) low[u] = min(low[u],dfn[v]);
	}
	if (low[u] == dfn[u]){
		cont++;
		while(1){
			int v = q.top(); q.pop();
			scc[v] = cont; 
			if (v == u) break;
		}
	}
}
vector<int>f[N];
int val[N],dis[N];
bool dep[N];
void spfa(int u){
	queue<int>Q;
	Q.push(u); dis[u] = val[u]; dep[u] = 1;
	while(!Q.empty()){
		int u = Q.front(); Q.pop(); dep[u] = 0;
		int ss = f[u].size();
 
		for (int i = 0; i < ss; ++i){
			int v = f[u][i];
			if (dis[v] < dis[u] + val[v]){
				dis[v] = dis[u] + val[v];
				if (dep[v] == 0){
					dep[v] = 1;
					Q.push(v);
				}
			}
		}
	}
}
int main(){
	init();
	Tarjan(S);
	int u,v;
	for (int i = 1; i <= n; ++i){
		u = scc[i];
		val[u] += Val[i];
		for (int j = Head[i]; j; j = Next[j]){
			v = scc[To[j]];
			if (v != u) 	f[u].push_back(v);
		}
	}
	spfa(scc[S]);
 
	int ans = 0;
	for (int i = 1; i <= n;++i)
		if (vis[i]) ans = max(ans,dis[scc[i]]);
	printf("%d\n",ans);
 
	return 0;
}
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值