推荐
题意
给定一个n个顶点,m条边的无向图,每条边有颜色值(长度均为1),求出起点到终点的最短路径(颜色值表示),若存在多解,则输出路径中颜色值字典序最小者。(注意重边,自环)
思路
逆向BFS求最短路径,正向BFS求字典序最小
代码如下
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
typedef long long ll;
typedef pair<int,int> PII;
int n,m;
struct Edge
{
int from,to,color;
};
vector<Edge>edges;
vector<int>G[maxn];
void init()
{
for(int i=0;i<=n;i++)
G[i].clear();
edges.clear();
}
void add(int from,int to,int color)
{
edges.push_back({from,to,color});
int m=edges.size();
G[from].push_back(m-1);
}
int d[maxn];
bool vis[maxn];
vector<int>ans;
void rev_bfs()
{
queue<int>q;
d[n]=0;
q.push(n);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<G[u].size();i++)
{
Edge e=edges[G[u][i]];
int v=e.to;
if(d[v]!=-1)
continue;
d[v]=d[u]+1;
q.push(v);
}
}
}
void bfs()
{
queue<int>q;
q.push(1);
while(!q.empty())
{
vector<int>V;//用来存符合之前条件的点
while(!q.empty())
{
V.push_back(q.front());
q.pop();
}
int mincolor=inf;
for(int i=0;i<V.size();i++)//先找最小颜色
{
int u=V[i];
for(int j=0;j<G[u].size();j++)
{
Edge e=edges[G[u][j]];
int v=e.to;
if(d[u]==d[v]+1)
mincolor=min(mincolor,e.color);
}
}
if(mincolor==inf)//说明只剩个终点了,返回
return;
ans.push_back(mincolor);
for(int i=0;i<V.size();i++)//再根据最小颜色,在所有点中找符合条件的
{
int u=V[i];
for(int j=0;j<G[u].size();j++)
{
Edge e=edges[G[u][j]];
int v=e.to;
if(d[u]==d[v]+1&&e.color==mincolor&&!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>n>>m)
{
init();
memset(d,-1,sizeof(d));
memset(vis,false,sizeof(vis));
ans.clear();
for(int i=0;i<m;i++)
{
int u,v,c;
cin>>u>>v>>c;
add(u,v,c);
add(v,u,c);
}
rev_bfs();
bfs();
cout<<ans.size()<<endl;
for(int i=0;i<ans.size();i++)
{
if(i==0)
cout<<ans[i];
else
cout<<" "<<ans[i];
}
cout<<endl;
}
}