1599 - Ideal Path

来源:互联网 发布:数组方法和字符串方法 编辑:程序博客网 时间:2024/04/30 22:16

New labyrinthattraction is open in New Lost land amusement park. The labyrinth consistsof nrooms connected by m passages. Each passageis colored into some color ci. Visitors of the labyrinthare dropped from the helicopter to the room number 1 and their goal is to getto the labyrinth exit located in the room number n.

Labyrinth ownersare planning to run a contest tomorrow. Several runners will be dropped to theroom number 1. They will run to the room number n writing downcolors of passages as they run through them. The contestant with the shortestsequence of colors is the winner of the contest. If there are severalcontestants with the same sequence length, the one with the ideal path isthe winner. The path is the ideal path if its color sequence is thelexicographically smallest among shortest paths.

Andrew ispreparing for the contest. He took a helicopter tour above New Lost land andmade a picture of the labyrinth. Your task is to help him find the ideal pathfrom the room number 1 to the room number n that would allowhim to win the contest.


Note:

A sequence (a1a2,..., ak) islexicographically smaller than a sequence (b1b2,..., bk) ifthere exists i such that ai < bi,and aj = bj forall j < i.

Input 

The input filecontains several test cases, each of them as described below.

The first line ofthe input file contains integers n and m --the number of rooms and passages, respectively (2n100000, 1m200000). Thefollowing m lines describe passages, each passage is describedwith three integer numbers: aibi,and ci -- the numbers of rooms it connects and itscolor (1aibin, 1ci109). Eachpassage can be passed in either direction. Two rooms can be connected with morethan one passage, there can be a passage from a room to itself. It isguaranteed that it is possible to reach the room number n fromthe room number 1.

Output 

For each testcase, the output must follow the description below.

The first line ofthe output file must contain k -- the length of the shortestpath from the room number 1 to the room number n. The second linemust contain k numbers -- the colors of passages in the orderthey must be passed in the ideal path.

SampleInput 

4 6

1 2 1

1 3 2

3 4 3

2 3 1

2 4 4

3 1 1

Sample Output 

2

1 3

代码:

#include<cstdio>

#include<cstring>

#include<vector>

#include<queue>

usingnamespace std;

 

constint maxn = 100000 + 5;//点的最大数目

constint INF = 1000000000;//颜色最大值

intn, vis[maxn];

intd[maxn];

vector<Edge>edges;//存储元素为结构体的数组

vector<int>G[maxn];

vector<int>ans;//存储顺序排列的答案的颜色数值

 

structEdge  //点的类型

{

    int u, v, c;//表示出发点为u,到达点为v,该边上的颜色大小 c

    Edge(int u=0, int v=0, intc=0):u(u),v(v),c(c) {}//默认构造函数

};

 

voidAddEdge(int u, int v, int c)

{

    edges.push_back(Edge(u, v, c));

intidx = edges.size() - 1;

//idx表示:插入的结构体在数组中的位置索引

G[u].push_back(idx);

//G[X]:存储出发点为X的边对应的结构体在edges数组中的索引,可以有多个

}

 

voidrev_bfs()//第一次反向宽搜:得到每个点距离终点的最短距离

{

    memset(vis, 0, sizeof(vis));//访问标记数组全部清空

    d[n-1] = 0;//终点距离本身的距离

    vis[n-1] = true;//已访问过终点

 

    queue<int> q;//宽搜开始,队列中存储点的编号

    q.push(n-1);

    while(!q.empty())

    {

        int v = q.front();

        q.pop();

       

        for(int i = 0; i < G[v].size(); i++)

//G[v].size()的大小是以点v为出发点即有点v的边的数目

        {

            int e = G[v][i];//边对应的结构体在数组中的索引

            int u = edges[e].v;

//edges[e]是边对应的结构体,u是边的另一个端点

            if(!vis[u])//点u没被访问过

            {

                vis[u] = true;//标记已访问

                d[u] = d[v] + 1;//距离增加1

                q.push(u);//压入队列

            }

        }

    }

}

 

voidbfs()//第二次正向宽搜,找出字典序最小的最短路

{

    memset(vis, 0, sizeof(vis));

    vis[0] = true;

    ans.clear();

 

    vector<int> next;//存储将要访问的点的编号

    next.push_back(0);

    for(int i = 0; i < d[0]; i++)

    {

        //首先找出最小的颜色大小

        int min_color = INF;

        for(int j = 0; j < next.size(); j++)

        {

            int u = next[j];//取出要访问的点的编号

            for(int k = 0; k < G[u].size();k++)

//遍历有点u的每一条边,找颜色最小大小

            {

                int e = G[u][k];

                int v = edges[e].v;

                if(d[u] == d[v] + 1)//如果是下一个距离的点,即保证在最短路上

                {

                    min_color = min(min_color,edges[e].c);

                }

            }

        }

        ans.push_back(min_color);

//位置必须在双重循环以外!!!找到与访问点相连的边的颜色的最小值

       

        //再找到应该访问的下一个点

        vector<int> next2;

        for(int j = 0; j < next.size(); j++)

        {

            int u = next[j];

            for(int k = 0; k < G[u].size();k++)

            {

                int e = G[u][k];

                int v = edges[e].v;

                if(d[u] == d[v] + 1 && !vis[v]&& edges[e].c == min_color)

//若在最短路上且没被访问过(保证不走重复的路)且两点边的颜色值是最小的

                {

                    vis[v] = true;

                    next2.push_back(v);

/*

将满足这些条件的点都存储下来,若有多个点,则记录所有这些点,走下一步时,要考虑所有从这些点出发的边

*/

                }

            }

        }

        next = next2;//更新要访问的点

    }

   

    //打印答案

    printf("%d\n", ans.size());

    printf("%d", ans[0]);

    for(int i = 1; i < ans.size(); i++)

    {

        printf(" %d", ans[i]);

    }

    printf("\n");

}

 

intmain()

{

    int u, v, c, m;

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

    {

        for(int i = 0; i < n; i++)

        {

            G[i].clear();//每组数据要清空

        }

       

        while(m--)

        {

            scanf("%d%d%d",&u, &v, &c);

            AddEdge(u-1, v-1, c);

//无向边相当于建立两个方向相反的有向边,索引从0开始

            AddEdge(v-1, u-1, c);

        }

       

        rev_bfs();//第一次反向宽搜:得到每个点距离终点的最短距离

       

        bfs();//第二次正向宽搜,找出字典序最小的最短路

    }

    return 0;

}

思路:

首先从节点n到节点1倒着BFS一次,算出每个节点到节点n个最短距离di然后从节点1开始再一次BFS,在寻找下一个节点时,必须满足下一个节点v满足对于当前节点u,有du = dv + 1,这样才能保证在最短路上。在这个条件下还要满足v的颜色编号是最小的。因为可能有多个颜色相同的最小编号,所以这些节点都要保留下来。图的表示方式:这里如果再用往常的邻接表发现不适用了,所以G[u]中保存的与u邻接的edges中边的编号。

 

0 0
原创粉丝点击