UVA1599-字典序+BFS

来源:互联网 发布:网络男生悲伤情歌 编辑:程序博客网 时间:2024/04/30 19:43

第一次写这么复杂的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 100005using 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;}

原创粉丝点击