UVa 1599 Ideal Path

来源:互联网 发布:北京和上海知乎 编辑:程序博客网 时间:2024/04/26 07:57

New labyrinth attraction is open in New Lostland amusement park. The labyrinth consists of n rooms connected by m passages. Each passage is colored into some color ci. Visitors of the labyrinth are dropped from the helicopter to the room number 1 and their goal is to get to the labyrinth exit located in the room number n.

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

Andrew is preparing for the contest. He took a helicopter tour above New Lostland and made a picture of the labyrinth. Your task is to help him find the ideal path from the room number 1 to the room number n that would allow him to win the contest.


Note:

A sequence (a1a2,..., ak) is lexicographically smaller than a sequence (b1b2,..., bk) if there exists i such that ai < bi, and aj = bj for all ji.

Input 

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

The first line of the input file contains integers n and m -- the number of rooms and passages, respectively (2$ \le$n$ \le$100000, 1$ \le$m$ \le$200000). The following m lines describe passages, each passage is described with three integer numbers: aibi, and ci -- the numbers of rooms it connects and its color (1$ \le$aibi$ \le$n, 1$ \le$ci$ \le$109). Each passage can be passed in either direction. Two rooms can be connected with more than one passage, there can be a passage from a room to itself. It is guaranteed that it is possible to reach the room number nfrom the room number 1.

Output 

For each test case, the output must follow the description below.

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

Sample Input 

4 6 1 2 11 3 23 4 32 3 12 4 43 1 1

Sample Output 

2 1 3
#include <cstdio>#include <vector>#include <queue>using namespace std;// 房屋节点结构体typedef struct h_node{int val;// 房屋号码// 如果visit为2代表已经访问过// 如果visit为1代表在队列中,还未访问// 如果visit为0代表不在队列中,还未访问int visit;/*struct h_node* child[100010];int weight[100010];*/vector<h_node*> child;vector<int> weight;//int child_num;vector<int> path;// 记录从1号房间到该房间的颜色路径int pre_val;// 记录颜色路径的前一个节点号码int pre_path;// 记录颜色路径的前一个节点到该节点的边长度int path_length; // 记录从1号房间到该房间的颜色路径长度}h_node;h_node node_array[100010];queue<h_node*> my_queue;int main(){int m, n;/*for(int i = 0; i < 100010; i++){h_node* p = (h_node*)malloc(sizeof(h_node));memset(h_node)}*/while(scanf("%d %d", &n, &m) == 2){for(int i = 1; i <= n; i++){node_array[i].val = i;//node_array[i].child_num = 0;node_array[i].child = vector<h_node*>();node_array[i].weight = vector<int>();node_array[i].path = vector<int>();node_array[i].visit = 0;}// 读入各个通道,记录权值最小的边for(int i = 1; i <= m; i++){int v1, v2, c;scanf("%d%d%d", &v1, &v2, &c);if(v1 != v2){int j;for(j = 0; j < node_array[v1].child.size(); j++){if(node_array[v1].child[j] == &node_array[v2]){if(node_array[v1].weight[j] > c)node_array[v1].weight[j] = c;break;}}if(j == node_array[v1].child.size()){node_array[v1].child.push_back(&node_array[v2]);node_array[v1].weight.push_back(c);}for(j = 0; j < node_array[v2].child.size(); j++)                                {                                        if(node_array[v2].child[j] == &node_array[v1])                                        {                                                if(node_array[v2].weight[j] > c)                                                        node_array[v2].weight[j] = c;                                                break;                                        }                                }                                if(j == node_array[v2].child.size())                                {                                        node_array[v2].child.push_back(&node_array[v1]);                                        node_array[v2].weight.push_back(c);                                }}}/*for(int i = 1; i <= n; i++){printf("now: %d: ", i);for(int j = 0; j < node_array[i].child.size(); j++)printf(" %d(%d)", node_array[i].child[j]->val, node_array[i].weight[j]);printf("\n");}*/// 进行宽度优先搜索,来得到与第n个房间的最理想路径node_array[1].visit = 1;node_array[1].path_length = 0;//node_array[1].path = my_queue = queue<h_node*>();my_queue.push(&node_array[1]);while(my_queue.size() > 0){h_node* p = my_queue.front();my_queue.pop();p->visit = 2;if(p == &node_array[n]){/*printf("%d\n", p->path.size());for(int i = 0; i < p->path.size(); i++){if(i == 0)printf("%d", p->path[i]);elseprintf(" %d", p->path[i]);}printf("\n");*/printf("%d\n", p->path_length);vector<int> now_path;h_node* q = p;while(q->val != 1){now_path.push_back(q->pre_path);q = &node_array[q->pre_val];}for(int j = now_path.size()-1; j >= 0; j--){if(j == now_path.size()-1)printf("%d", now_path[j]);elseprintf(" %d", now_path[j]);}printf("\n");break;}// 将所有未访问过,不在队列中的节点加入队列,// 如果该节点在队列中,更新其路径for(int i = 0; i < p->child.size(); i++){if(p->child[i]->visit == 0){p->child[i]->visit = 1;/*p->child[i]->path = p->path;p->child[i]->path.push_back(p->weight[i]);*/p->child[i]->pre_val = p->val;p->child[i]->pre_path = p->weight[i];p->child[i]->path_length = p->path_length+1;/*for(int k = 0; k < p->path.size(); k++)p->child[i]->path.push_back(p->path[k]);p->child[i]->path.push_back(p->weight[i]);*/my_queue.push(p->child[i]);}else if(p->child[i]->visit == 1) {int fresh_flag = 0;if(p->path_length + 1 < p->child[i]->path_length)fresh_flag = 1;else if(p->path_length+1 == p->child[i]->path_length){//printf("here: %d %d\n", p->val, p->child[i]->val);// 观察两个路径谁大vector<int> path1;vector<int> path2;path1.push_back(p->weight[i]);path2.push_back(p->child[i]->pre_path);h_node* p1 = p;h_node* p2 = &node_array[p->child[i]->pre_val];//printf("p1->val: %d, p2->val: %d\n", p1->val, p2->val);while(p1->val != 1 && p2->val != 1){//printf("p1->val: %d, p2->val: %d\n", p1->val, p2->val);path1.push_back(p1->pre_path);path2.push_back(p2->pre_path);p1 = &node_array[p1->pre_val];p2 = &node_array[p2->pre_val];}int bigger_flag = 0;for(int j = path1.size()-1; j >= 0; j--){//printf("p1: %d  p2: %d\n", path1[j], path2[j]);if(path1[j] < path2[j]){bigger_flag = -1;break;}else if(path1[j] > path2[j]){bigger_flag = 1;break;}}if(bigger_flag == -1){fresh_flag = 1;}}if(fresh_flag){p->child[i]->pre_val = p->val;p->child[i]->path_length = p->path_length+1;p->child[i]->pre_path = p->weight[i];} /*if(p->path.size()+1 < p->child[i]->path.size())fresh_flag = 1;else if(p->path.size()+1 == p->child[i]->path.size()){int m;for(m = 0; m < p->path.size(); m++){if(p->path[m] > p->child[i]->path[m])break;}if(m == p->path.size() && p->weight[i] < p->child[i]->path[p->child[i]->path.size()-1]){fresh_flag = 1;}}if(fresh_flag){p->child[i]->path = p->path;p->child[i]->path.push_back(p->weight[i]);}*/}}}}return 0;}


这道题一开始思路比较明确:
理想路径首先肯定是步数最短,再考虑颜色权值最小。
主体是BFS, 唯一需要注意的是:假设当前点是p,  1到p的颜色路径已经确定,那么p指向的节点q,
如果q已经在BFS队列中了,也可能需要更新1到q的颜色路径。有且只有这个时候有更新的必要。
PS: 一开始一直TLE, 以为方法错,后来看书发现介绍的方法是从终点BFS,或者两次BFS. 
一直不相信自己从起点一次BFS会错,后来发现是效率不高,将小细节修改了一下就通过了。
所以,该方法从起点一次BFS也可以!
0 0
原创粉丝点击