/*
题意:给定无向图(有重边)每条边有一种颜色,边权为1,让你找到从1到n的最短路,并且
经过的边的颜色组成的序列的字典序最小。
解答:1 分别spfa求出所有点到1和n的最短路d[0][i],d[1][i](可能经过的边u-v满足d[0][u]+1+d[1][v]=d[0][n])。
2 bfs搜索最小的字典序序列,找出C[step]的最小颜色序号
*/
const int M=100009;
const int N=400009;
const int INF=1<<30;
int n,m;
struct Edge
{
int v,next,c;
}edge[N];
int first[M],e,vis[M],d[2][M];
void addedge(int u,int v,int c)
{
edge[e].v=v;
edge[e].c=c;
edge[e].next=first[u];
first[u]=e++;
edge[e].v=u;
edge[e].c=c;
edge[e].next=first[v];
first[v]=e++;
}
void init()
{
scanf("%d%d",&n,&m);
int u,v,c;
memset(first,-1,sizeof(first));
e=0;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&c);
addedge(u,v,c);
}
}
int spfa(int x,int id)
{
for(int i=1;i<=n;i++)
d[id][i]=INF,vis[i]=0;
d[id][x]=0;
vis[x]=1;
queue<int> q;
q.push(x);
while(!q.empty())
{
int x=q.front();q.pop();
vis[x]=0;
for(int k=first[x];k!=-1;k=edge[k].next)
{
int v=edge[k].v;
if(d[id][v]>d[id][x]+1)
{
d[id][v]=d[id][x]+1;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return d[id][n];
}
struct point
{
int step;
int v;
point(){}
point(int _v,int _step){v=_v,step=_step;}
}Qu[M],Q[M];
int fa[M];
void solve()
{
printf("%d\n",spfa(1,0));
spfa(n,1);
for(int i=1;i<=n;i++)
vis[i]=0;
Qu[0]=point(1,0);//Qu保存经过step步最小序列能到的点
int L=0,R=1;
int flag=1;
while(L<R)
{
int x=Qu[L].v;
int step=Qu[L].step;
if(step==d[0][n])break;
int tmp=1<<30,num=0;
for(int i=L;i<R;i++)//遍历第step能经过的边,找出最小颜色
{
int xx=Qu[i].v;
if(Qu[i].step!=step)break;
for(int k=first[xx];k!=-1;k=edge[k].next)
{
int v=edge[k].v;
if(d[0][xx]+1+d[1][v]==d[0][n])
{
if(edge[k].c<tmp)
{
tmp=edge[k].c;
Q[0]=point(v,step+1);
num=0;
}
else if(edge[k].c==tmp)//最小颜色的边有多个,出入Q中
{
if(!vis[v])//不重复放入,没有这个优化会tle
{
vis[v]=1;
Q[++num]=point(v,step+1);
}
}
}
}
}
if(flag) {printf("%d",tmp);flag=0;}
else printf(" %d",tmp);
R=0;
for(int i=0;i<=num;i++)//把下一步能到的点出入Qu;
{
Qu[R++]=(Q[i]);
}
L=0;
}
puts("");
}
int main()
{
int ca;
scanf("%d",&ca);
while(ca--)
{
init();
solve();
}
return 0;
}
HDU 3760 Ideal Path 最短路spfa+BFS 字典序最小的最短路
最新推荐文章于 2020-12-09 15:01:13 发布