题目链接
这道题利用两次BFS来求解:
- 由于题目有两个限制条件:最短路径,字典序颜色,假设我们从后往前BFS,将得到每个节点到终点的步数,这样就知道起点到终点的步数,同时中间的路径也可以由每次递减来确定,第二次BFS中维护最小字典序即完成。
- 输入涉及到重复和自环,要避免重复和过滤自环。
- 由于数量级很大采用邻接表存储数据。
C++代码描述
#include<bits/stdc++.h>
using namespace std;
const int maxn=100000;
const int inf=0x7fffffff;
int d[maxn],res[maxn];
bool vist[maxn],inqueue[maxn];
int n,m,v;
struct Node{
int link,color;
Node(int l,int c):link(l),color(c){}
};//节点定义
vector<Node> linklist[maxn];//邻接表定义
void dfs(int start,int end){
memset(inqueue,0,sizeof(inqueue));
memset(vist,0,sizeof(vist));
queue<int> q;
q.push(start);
if(start){
while(!q.empty()){
int u=q.front();q.pop();vist[u]=1;
for(int i=0;i<linklist[u].size();i++)
if(!vist[v=linklist[u][i].link]&&!inqueue[v]){
d[v]=d[u]+1;
if(v==0) return;
q.push(v);
inqueue[v]=1;
}
}
}else{
memset(res,0,sizeof(int)*n);
while(!q.empty()){
int u=q.front();q.pop();vist[u]=1;
if(u==n-1) return;
int minc=inf;
for(int i=0;i<linklist[u].size();i++)if(!vist[v=linklist[u][i].link]&&d[v]==d[u]-1)minc=min(minc,linklist[u][i].color);
for(int i=0;i<linklist[u].size();i++)if(!vist[v=linklist[u][i].link]&&d[v]==d[u]-1&&!inqueue[v]&&linklist[u][i].color==minc)inqueue[v]=1,q.push(v);
int index=d[0]-d[u];
if(res[index]==0) res[index]=minc;
else res[index]=min(res[index],minc);
}
}
}
int main(){
// freopen("F://inp.txt","r",stdin);
while(cin>>n>>m){
for(int i=0;i<n;i++) linklist[i].clear();
memset(d,-1,sizeof(d));d[n-1]=0;
while(m--){
int a,b,c;
cin>>a>>b>>c;
if(a!=b){
linklist[a-1].push_back(Node(b-1,c));
linklist[b-1].push_back(Node(a-1,c));
}
}
dfs(n-1,0);
dfs(0,n-1);
cout<<d[0]<<endl<<res[0];
for(int i=1;i<d[0];i++) cout<<" "<<res[i];
cout<<endl;
}
return 0;
}