UVa 1599 Ideal Path

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 1
1 3 2
3 4 3
2 3 1
2 4 4
3 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]);
					else
						printf(" %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]);
					else
						printf(" %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也可以!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值