全源最短路johnson板子

#include<bits/stdc++.h>
#define int long long
#define ll long long
using namespace std;
const ll inf=1e16;
#define N 1000005
int n,m;
struct edge{int v,w;};
vector<edge> e[N];
int vis[N],cnt[N];
int h[N],d[N];
void spfa(){
	queue<int>q;
	for(int i=1;i<=n;i++) h[i]=inf;
	for(int i=1;i<=n;i++) cnt[i]=vis[i]=0;
	h[0]=0,vis[0]=1;q.push(0);
	while(q.size()){
		int u=q.front(); q.pop();vis[u]=0;
		for(auto ed : e[u]){
			int v=ed.v,w=ed.w;
			if(h[v]>h[u]+w){
				h[v]=h[u]+w;
				cnt[v]=cnt[u]+1;
				if(cnt[v]>n){
					printf("-1\n");exit(0);
				}
				if(!vis[v])q.push(v),vis[v]=1;
			}
		}
	}
}
void dijkstra(int s){
	priority_queue<pair<int,int>>q;
	for(int i=1;i<=n;i++) d[i]=inf;
	for(int i=1;i<=n;i++) vis[i]=0;
	d[s]=0; q.push({0,s});
	while(q.size()){
		int u=q.top().second;q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		for(auto ed:e[u]){
			int v=ed.v,w=ed.w;
			if(d[v]>d[u]+w){
				d[v]=d[u]+w;
				if(!vis[v]) q.push({-d[v],v});
			}
		}
	}
}

void solve(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) e[i].clear();
	
	for(int i=0;i<m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		e[u].push_back({v,w});
		e[v].push_back({u,w});
	}
	vector<int>t(n+1);
	for(int i=1;i<=n;i++) cin>>t[i];
	
	for(int i=1;i<=n;i++){
		e[0].push_back({i,0});//加虚拟边
	}
	spfa();
	for(int u=1;u<=n;u++)
		for(auto &ed:e[u])
			ed.w+=h[u]-h[ed.v];//构造新边
	//f[i][j]表示i->j的最短路    
	vector<vector<int>>f(n+1,vector<int>(n+1));
	for(int i=1;i<=n;i++){
		dijkstra(i);
		for(int j=1;j<=n;j++){
			f[i][j]=d[j]+h[j]-h[i];
		}
	}
	//以上都是johnson板子
	vector<int>mnd(n+1,inf);
	auto bfs=[&](int s){
		for(int i=1;i<=n;i++) vis[i]=0;
		priority_queue<pair<int,int>>pq;
		pq.push({0,s});mnd[s]=0;
		while(pq.size()){
			int u=pq.top().second;pq.pop();
			if(vis[u]) continue;
			vis[u]=1;
			for(int v=1;v<=n;v++){
				if(vis[v]) continue;
				if(mnd[u]+f[u][v]*t[u]<mnd[v]){
					mnd[v]=mnd[u]+f[u][v]*t[u];
					pq.push({-mnd[v],v});
				}
			}
		}
	};
	bfs(1);
	cout<<mnd[n]<<'\n';
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值