满分做法:
在做搜索 最短路路径时 可以从终点搜到起点,记录该位置到终点的最短路,再次搜索时从起点搜索并判断即可。
本题还要比较颜色的字典序,于是我们把当前深度的点都拿出来,进行向外扩展,找到既在最短路径上,又经过颜色字典序最小的点,加入到队列中,并把当前颜色最小值加入到答案序列即可。
#include<queue>
#include<cmath>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxm=4e5+7;
int n,m;
int pre[maxm],last[100007],other[maxm],len[maxm],l;
int dis[100007];
bool vis[100007];
vector<int > ans;
void add(int x,int y,int z)
{
l++;
pre[l]=last[x];
last[x]=l;
other[l]=y;
len[l]=z;
}
void bfs()//反向找最短路,便于第二次bfs找到最短路径
{
dis[n]=0;
queue<int >q;
q.push(n);
while(q.size())
{
int u=q.front();
q.pop();
for(int p=last[u];p;p=pre[p])
{
int v=other[p];
if(dis[v]!=-1) continue;
dis[v]=dis[u]+1;
q.push(v);
}
}
}
void bfs1()
{
queue<int > q;
q.push(1);
vis[1]=1;
while(q.size())
{
vector<int> c;
while(q.size())
{
c.push_back(q.front());
q.pop();
}
int minn=1e9+7;
for(int i=0;i<c.size();i++)
{
int u=c[i];
for(int p=last[u];p;p=pre[p])
{
int v=other[p];
if(dis[v]+1==dis[u])
{
minn=min(minn,len[p]);
}
}
}
if(minn==1e9+7) return;//扩展完全
ans.push_back(minn);
for(int i=0;i<c.size();i++)
{
int u=c[i];
for(int p=last[u];p;p=pre[p])
{
int v=other[p];
if(dis[v]+1==dis[u]&&len[p]==minn&&!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
memset(dis,-1,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(last,0,sizeof(last));
l=0;
ans.clear();
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
bfs();
bfs1();
printf("%d
",ans.size());
for(int i=0;i<ans.size();i++)
printf("%d%c",ans[i],i+1==(int)ans.size()?'
':' ');
}
return 0;
}