Link

如何处理起点和终点呢?

先从终点搜,维护每个点到终点的距离

再从起点搜,每次从当前点,先选能到终点更近一步的边,再从这些边中,选出字母最小的所有边,加进集合中,直至搜到终点,就是字典序最小的最短路

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10,M=2*N;
int n,m;
int h[N],e[M],ne[M],idx;
char w[M];
void add(int a,int b,char c){
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
    
}
int q[N];
int hh,tt;
int d[N];
int sp,last[N];
string res;
set<int> stt,nxt;
char cur;
void bfs(){
    q[0]=n;
    d[n]=1;
    while(hh<=tt){
        int c=q[hh++];
        for(int i=h[c];~i;i=ne[i]){
            int k=e[i];
            if(d[k])continue;
            d[k]=d[c]+1;
            q[++tt]=k;
        }
    }
}
void bfs2(){
    stt.insert(1);
    while(1){
        cur='z'+1;
        for(auto ver:stt){
            if(ver==n)return ;
            for(int i=h[ver];~i;i=ne[i]){
                int k=e[i];
                if(d[k]==d[ver]-1){
                    if(w[i]<cur)nxt.clear(),nxt.insert(k),last[k]=ver,cur=w[i];
                    else if(w[i]==cur)nxt.insert(k),last[k]=ver;
                }
            }
        }
        stt.clear();
        for(auto ver:nxt)stt.insert(ver);
        nxt.clear();
        res+=cur;
        sp++;
    }
}
int main()
{
    memset(h, -1, sizeof h);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int a,b;
        char op[2];
        scanf("%d%d%s",&a,&b,op);
        add(a,b,*op),add(b,a,*op);
    }
    bfs();
    bfs2();
    cout<<sp<<endl;
    vector<int>path;
    int now=n;
    while(now!=1)path.push_back(now),now=last[now];
    path.push_back(1);
    reverse(path.begin(),path.end());
    for(auto it:path)cout<<it<<' ';
    cout<<endl<<res<<endl;
    
}