如何处理起点和终点呢?
先从终点搜,维护每个点到终点的距离
再从起点搜,每次从当前点,先选能到终点更近一步的边,再从这些边中,选出字母最小的所有边,加进集合中,直至搜到终点,就是字典序最小的最短路
#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;
}
浙公网安备 33010602011771号