UVA1599-字典序+BFS

第一次写这么复杂的bfs,卡了我近一周,需要注意的细节很多,很多地方感觉跟题解差不多,但是就是不对。失之毫厘谬以千里啊。

这里是原题
这里是我当时看的一个比较好的题解(里面用的指针我不懂 但思路非常棒)

大概做法

先从n开始bfs,得到每个点到n的最短距离d[i]。然后从起点开始bfs,每一步保证d[v]=d[u]-1,同时储存最小字典序

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define maxn 100005
using namespace std;
typedef struct edge{
    int col,to;
    edge(int a,int b):to(a),col(b){}

}Edge;
vector <Edge>e[maxn];  //邻接表储存图
int n,m,u,v,c,d[maxn],ans[maxn*4];//uvc是临时变量 个人习惯
bool vis[maxn];
void init()
{
    memset(ans,0x3f,sizeof ans);
    memset(d,-1,sizeof d); 
    memset(vis,0,sizeof vis);
    for (int i=1;i<=n;i++)e[i].clear(); 

    for(int i=1;i<=m;++i){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        if(a==b)continue;
        e[a].push_back(edge(b,c));
        e[b].push_back(edge(a,c));  //双向边   
    } 

    return ;

}
void fbfs(){

    queue<int >q;
    q.push(n);
    d[n]=0;
    while(!q.empty()){
        u=q.front();
        q.pop();
    //  if(u==1){return ;}这里建议大家把图遍历全,不要贪图那一点点时间,不然会出现玄学bug

        for(int i=0,len=e[u].size();i<len;++i){
            v=e[u][i].to;
            if(d[v]!=-1)continue;//不重复访问 写过复杂图bfs的应该都懂
            d[v]=d[u]+1;
            q.push(v);
        }
    }
    return ;
}
void bfs(){
/*
这个题有一点很重要,需要先在这里说明,一不能简单更新ans(见图2),二每个点会入队多遍但只会访问一遍(见题中样例,如果每个点只入队一遍就会错过后来的更优解)
这些在我下面的代码里都有所体现
*/
    queue<pair<int,int> >q;  //这里很秒 first 储存节点编号,second储存访问到达这个节点的边的颜色  我也是看别人代码学会的
    q.push(make_pair(1,0));
    ans[0]=0;//
    while(!q.empty()){
        u=q.front().first;
        c=q.front().second;

        q.pop();
        if(ans[d[1]-d[u]]!=c||u==n||vis[u])continue;
        //一满足沿着最短路线走 二别走过  三只访问一遍即可
        vis[u]=1;


        for(int i=0,len=e[u].size();i<len;++i){

            v=e[u][i].to;
            c=e[u][i].col;
            if(d[u]!=d[v]+1||c>=ans[d[1]-d[v]])continue;
            ans[d[1]-d[v]]=c;//更新第(d[1]-d[v])步最小颜色
        }

        for(int i=0,len=e[u].size();i<len;++i){
            v=e[u][i].to;
            c=e[u][i].col;
            if(d[u]!=d[v]+1||c!=ans[d[1]-d[v]])continue;  //如果有多个当前最优解 把他们全部入队
            q.push(make_pair(v,c));

        }
        //有可能当前阶段有多个解能到达点i,但到达点i的路径颜色不同或相同,这时就会通过开头的剪枝,将他们去掉  因为将该层遍历完后一定能得到最优解的颜色   就可以通过比较ans[]只访问最优解, 并通过vis只访问一次最优解


    }


}
int main(){

    while(scanf("%d%d",&n,&m)==2){

    init();

    fbfs();//从n开始

    bfs();//从1开始

    printf("%d\n", d[1]);  
        for (int i = 1; i<=d[1]; i++)  
            printf("%d%c",ans[i],i==d[1]?'\n':' ');

    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值