您的位置:首页 > 其它

JZOJ 5279 香港记者

2017-08-28 20:08 267 查看


一句话题意:一个带点权边权的无向图,输出从1号点到n号点的最短路中字典序最小的一条路径

样例输入:

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

样例输出:

6
1 4 5 8

思路:

跑一边spfa(单源最快),更新条件改成(当前路径更短 or (当前路径和原路径相等 and 当前路径字典序更小)),直接开一个pre数组维护当前点的前继就好。

建议自己写队列,实现只要两分钟(因为代码短),而且不会被卡STL(实际上也没什么变态出题人会去卡一个queue),习惯第一。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
struct edge{
int next,to,w;
edge(){
to=w=0;next=-1;
}
}a[400100];
int n,m,first[200100],bk[200100];
ll dis[200100];bool vis[200100];
ll pre[200100];
struct Queue{
int q[300100],head,tail;
Queue(int k){
head=100000;tail=100001;memset(q,0,sizeof(q));
q[head]=k;
}
void push(int k){
if(dis[k]>dis[q[head]]) q[tail++]=k;
else q[--head]=k;
}
void pop(){
q[head++]=0;
}
int top(){
return q[head];
}
bool empty(){
return (head==tail);
}
};
void spfa(){
Queue q(n);
vis
=1;dis
=0;pre
=n;
int u,v,w,i;
while(!q.empty()){
u=q.top();q.pop();vis[u]=0;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;w=a[i].w;
if(dis[v]>dis[u]+w||(dis[v]==dis[u]+w&&bk[pre[v]]>=bk[u])){
dis[v]=dis[u]+w;
pre[v]=u;
if(!vis[v]){
vis[v]=1;q.push(v);
}
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
first[i]=-1;dis[i]=0x3f3f3f3f3f3f3f;
scanf("%d",&bk[i]);
}
int t1,t2,t3;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&t1,&t2,&t3);
a[i].to=t1;a[i].next=first[t2];a[i].w=t3;first[t2]=i;
}
spfa();
printf("%lld\n%d ",dis[1],bk[1]);
int i=1;
while(i!=n){
printf("%d ",bk[pre[i]]);i=pre[i];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: