題目鏈接
這道題利用兩次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;
}