算法竞赛入门经典 例题6-20

UVa1599

Ideal Path

房间和房间之间存在路径,路径的颜色用整数表示,找到一个从编号为1的房间到编号为n的房间的一条理想路径。理想路径是字典序最小的路径。

  1. 虽然房间数量多达100000,但我还是试了一下朴素的深搜,超时了
  2. 然后我又试了朴素的广搜,并在广搜过程中记录了从房间1到各个房间的理想路径,还是超时了。相对于穷举全部理想路径的深搜,广搜只需要穷举全部最短的理想路径
  3. 为了省事,上面两种方法都是用的邻接矩阵存储的图,所以我又把广搜中的邻接矩阵换成邻接表试了一下(为了去掉重复的路径,其实邻接的是map),还是超时了,但此时uDebug上超长的测试用例已经可以在很短的时间内跑出来了,这是因为广搜每一次扩展时访问的节点数量已经少很多很多了
  4. 广搜已经是最优了,还能优化的就是只求解房间1到房间n的理想路径,所以我又改成了从编号为n的房间反向广搜来统计各个房间到房间n的最短路径长度,然后通过一次从房间1开始的正向的迭代来求理想路径——以上就是网上各种两次BFS题解的分析思路
  5. 最后收获了一个PE,因为输出路径时最后一个颜色值后面多加了空格。
#include <iostream>
#include <algorithm>
#include <climits>
#include <deque>
#include <map>
#include <set>
#include <vector>

using namespace std;

class Solution
{
public:
	Solution(const vector<map<size_t, size_t>> &rooms) 
		: graph(rooms), levels(rooms.size(), UINT_MAX), visited(rooms.size(), false)
	{
		SearchIdealPath();
	}
	void print(ostream &os)
	{
		os << IdealPath.size() << endl;
		cout << IdealPath.front();
		for(size_t i = 1; i < IdealPath.size(); i++)
		{
			cout << ' ' << IdealPath[i];
		}
		cout << endl;
	}
private:
	const vector<map<size_t, size_t>> &graph;
	vector<size_t> levels, IdealPath;
	vector<bool> visited;
	void SearchIdealPath()
	{
		deque<size_t> q;
		visited.back() = true;
		q.push_back(graph.size() - 1);
		levels.back() = 0;
		while (!q.empty()) {
			size_t curr = q.front();
			q.pop_front();
			if (curr == 0) break;
			for (auto iter = graph[curr].begin(); iter != graph[curr].end(); iter++)
			{
				if (!visited[iter->first]) {
					visited[iter->first] = true;
					q.push_back(iter->first);
					levels[iter->first] = levels[curr] + 1;
				}
			}
		}
		set<size_t> SameColor{ 0 };
		while (1) {
			size_t MinColor = UINT_MAX;
			set<size_t> NextSameColor;
			for (size_t curr : SameColor)
			{
				for (auto iter = graph[curr].begin(); iter != graph[curr].end(); iter++)
				{
					if (levels[iter->first] == levels[curr] - 1) {
						if (iter->second < MinColor) {
							NextSameColor.clear();
							NextSameColor.insert(iter->first);
							MinColor = iter->second;
						}
						else if (iter->second == MinColor) {
							NextSameColor.insert(iter->first);
						}
					}
				}
			}
			IdealPath.push_back(MinColor);
			if (IdealPath.size() == levels.front()) break;
			SameColor = NextSameColor;
		}
	}
};

int main()
{
	size_t n, m;
	while (cin >> n) {
		cin >> m;
		vector<map<size_t, size_t>> rooms(n);
		for (size_t i = 0; i < m; i++)
		{
			size_t a, b, c;
			cin >> a >> b >> c;
			if (a == b) continue;
			auto iter = rooms[a - 1].find(b - 1);
			if (iter == rooms[a - 1].end()) {
				rooms[a - 1][b - 1] = c;
				rooms[b - 1][a - 1] = c;
			}
			else if(c < iter->second){
				iter->second = c;
				rooms[b - 1][a - 1] = c;
			}
		}
		Solution solution(rooms);
		solution.print(cout);
	}
	return 0;
}
/*
4 6
1 2 1
1 3 2
3 4 3
2 3 1
2 4 4
3 1 1
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值