UPC-2020.2.25第二十五场M题-香港记者(最短路+还原路径)-SPFA/Dijkstra算法

帅气的光光学长给我讲了这个题的路径还原和背包路径还原一样才想到的

题目描述

众所周知,香港记者跑得比谁都快,这其中其实是有秘诀的。
首先他们会跑最短路,但是最短路会有很多条,而且其他记者也知道要跑最短路,香港记者还统计出了每座城市带黑框眼镜的人数,如果一个记者跑路的时候城市带黑框眼镜人数的序列字典序比另一个记者大,那么这个记者就会被不可描述的力量续走时间,导致他跑得没字典序小的记者快。
长者日理万机,想请你告诉他香港记者经过的总路程和城市带黑框眼镜人数的序列,方便他找到香港记者,传授他们一些人生经验。
方便起见,设起点为 1 终点为 n。
由于不可描述的力量,各个城市带黑框眼镜的人数各不相同。
输入
第一行,两个整数n,m表示有n个城市,城市之间有m条有向边。
第二行,n个数,表示每个城市带黑框眼镜的人数bi;
接下来m行,每行3个非负整数ui,vi,wi表示一条有向边的起点,终点,路程。
输出
第一行,一个非负整数表示香港记者经过的总路程。
第二行,若干个非负整数表示香港记者经过的城市带黑框眼镜人数的序列。

样例输入 Copy

8 9
1 2 3 4 5 6 7 8
1 2 2
2 3 3
3 8 3
1 4 3
4 5 2
5 8 1
1 6 1
6 7 2
7 8 3

样例输出 Copy

6
1 4 5 8

提示

2≤n≤2×105,1≤m≤4×105,1≤w≤1×109,存在至少一条从起点到终点的最短路。

题目分析

2e5个点,可以用解法一迪杰斯特拉的队列优化和解法二SPFA
要求还原路径的字典序最小。
我想到背包问题求方案数也是还原字典序最小的路径
当时采用的是从最后一个背包开始向前遍历。
这个题的话,我们可以逆向存储边的信息找一条从N到1的最短路,

既然要还原路径,我们新设一个数组pre[n] 表示n这个点的上一个点,

如果
dist[v]>dist[u]+w(u,v)

dist[v]=dist[u]+w(u,v);
如果
dist[v]==dist[u]+w(u,v)
此时若pre[v]的点权大于u的点权,我们将
pre[v]=u;

CODE 1

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define  gold_m main
#define re register
#define Accept return 0;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//const int inf =0x3f3f3f3f;
const ll  inf =0x3f3f3f3f3f3f3f;
const int maxn=1e6+5;
const int mod = 1e9+7;
const int N = 666;
const long double PI=3.1415926535897932384626433832795;
//const long double e=2.71828182845904523536028747135266;
typedef pair<ll,ll>PII;
inline ll read() {
    
    
	ll  x=0;
	bool f=0;
	char ch=getchar();
	while (ch<'0'||'9'<ch)	f|=ch=='-', ch=getchar();
	while ('0'<=ch && ch<='9')
		x=x*10+ch-'0',ch=getchar();
	return f?-x:x;
}
//priority_queue<int,vector<int>, greater<int> >heap;
//stack<int>st;
ll  n,m,a[maxn],cnt,head[maxn],dist[maxn],st[maxn],pre[maxn],path[maxn];
struct wmy {
    
    
	ll u,v,w,next;
} e[maxn];
void add(ll u ,ll v,ll w) {
    
    
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].w=w;
	e[cnt].next=head[u];
	head[u]=cnt++;
}
ll  Dijkstra() {
    
    
	priority_queue<PII,vector<PII>,greater<PII>>heap;
	dist[n]=0;
	heap.push({
    
    0,n});
	while(!heap.empty()) {
    
    
		auto fr=heap.top();
		heap.pop();
		ll u=fr.second;
		ll w=fr.first;
		if(st[u]) continue;
		st[u]=1;
		for(int j=head[u]; j!=-1; j=e[j].next) {
    
    
			ll t= e[j].v;
			if(dist[t]>w+e[j].w||(dist[t]==e[j].w+dist[u]&&a[u]<=a[pre[t]])) {
    
    
				dist[e[j].v]=w+e[j].w;
				pre[e[j].v]=u;
				heap.push({
    
    dist[e[j].v],e[j].v});
			}
		}
	}
	
return dist[1];

}
int   gold_m() {
    
    
	memset(head,-1,sizeof(head));
	memset(pre,-1,sizeof(pre));
	n=read();
	m=read();
	for(int i=1 ; i<=n ; i++) a[i]=read(),dist[i]=inf;
	for(int i=1 ; i<=m; i++) {
    
    
		ll u,v,w;
		u=read();
		v=read();
		w=read();
		add(v,u,w);
	}
	cout<<Dijkstra()<<endl<<a[1]<<" ";
	int i=1;
	while(i!=n) {
    
    
		printf("%d ",a[pre[i]]);
		i=pre[i];
	}
	Accept;
}
/*
8 9
1 2 3 4 5 6 7 8
1 2 2
2 3 3
3 8 3
1 4 3
4 5 2
5 8 1
1 6 1
6 7 2
7 8 3
*/

CODE 2

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define  gold_m main
#define re register
#define Accept return 0;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//const int inf =0x3f3f3f3f;
const ll  inf =0x3f3f3f3f3f3f3f;
const int maxn=2e6+15;
const int mod = 1e9+7;
const int N = 666;
const long double PI=3.1415926535897932384626433832795;
//const long double e=2.71828182845904523536028747135266;
typedef pair<ll,ll>PII;
inline ll read() {
    
    
	ll  x=0;
	bool f=0;
	char ch=getchar();
	while (ch<'0'||'9'<ch)	f|=ch=='-', ch=getchar();
	while ('0'<=ch && ch<='9')
		x=x*10+ch-'0',ch=getchar();
	return f?-x:x;
}
//priority_queue<int,vector<int>, greater<int> >heap;
//stack<int>st;
ll  n,m,a[maxn],cnt,head[maxn],dist[maxn],st[maxn],pre[maxn],path[maxn];
struct wmy {
    
    
	ll u,v,w,next;
} e[maxn];
bool cmp(wmy x,wmy y) {
    
    
	if(x.u!=y.u) return x.u<y.u;
	else return a[x.v]>a[y.v];
}
void add(ll u ,ll v,ll w) {
    
    
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].w=w;
	e[cnt].next=head[u];
	head[u]=cnt++;
}
priority_queue<PII,vector<PII>,greater<PII>>heap;
void spfa() {
    
    
	for(int i=1 ; i<=n; i++) dist[i]=inf;
	dist[n]=0;
	st[n]=1;
//	pre[n]=n;
	queue<ll>q;
	q.push(n);
	while(!q.empty()) {
    
    
		ll u=q.front();
		q.pop();
		st[u]=0;
		for(int i=head[u]; i!=-1; i=e[i].next) {
    
    
			ll t=e[i].v;
			if(dist[t]>e[i].w+dist[u]||(dist[t]==e[i].w+dist[u]&&a[u]<=a[pre[t]])) {
    
    
				dist[t]=e[i].w+dist[u];
				pre[t]=u;
				if(st[t]==0) {
    
    
					st[t]=1;
					q.push(t);
				}
			}
		}
	}
}

int   gold_m() {
    
    
	memset(head,-1,sizeof(head));
//	memset(pre,-1,sizeof(pre));
	scanf("%lld%lld",&n,&m);
	for(ll i=1 ; i<=n ; i++)scanf("%lld",&a[i]);

	for(int i=1 ; i<=m; i++) {
    
    
		ll u,v,w;
		scanf("%lld%lld%lld",&u,&v,&w);
		add(v,u,w);
	}
	spfa();
	printf("%lld\n%lld ",dist[1],a[1]);
	int i=1;
	while(i!=n) {
    
    
		printf("%d ",a[pre[i]]);
		i=pre[i];
	}
	Accept;
}
/*
8 9
1 2 3 4 5 6 7 8
1 2 2
2 3 3
3 8 3
1 4 3
4 5 2
5 8 1
1 6 1
6 7 2
7 8 3


*/

猜你喜欢

转载自blog.csdn.net/wmy0536/article/details/104494470