UVA Ideal Path

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 101000;
const int inx = 1 << 30;
bool vis[maxn];
int d[maxn],n,m;//存储最短路径
vector<int>g[maxn];
struct edge
{
	int u, v, c;
	edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){}//存储路径,注意颜色作为权值储存
};
vector<edge>map;
void build(int u,int v,int c)
{
	map.push_back(edge(u, v, c));//map数组存储所有连通的情况
	int record = (int)map.size() - 1;
	g[u].push_back(record);//记录有几条边存在连通关系
}
void re_bfs()//反向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 u = q.front(); q.pop();
		for (int i = 0; i < g[u].size(); i++)
		{
			int count = g[u][i];
			int v= map[count].v;//从终点开始bfs寻找下一个节点,计算路径
			if (!vis[v])
			{
				vis[v] = true;
				d[v] = d[u] + 1;//永远保证所求路径为最短路径
				q.push(v);//下一个节点进入判断寻找
			}
		}
	}
}
vector<int>ans;
void bfs()
{
	memset(vis, 0, sizeof(vis));
	ans.clear();
	vis[0] = true;
	vector<int>next;
	next.push_back(0);//从起点开始寻找,注意取点时的控制
	for (int i = 0; i < d[0]; i++)//d[0]代表求出的最短路径
	{
		int min_color = inx;//寻找最小的颜色,及所有满足条件的点中最小的权值
		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];//g[u][k]用于取出map中的元素
				int v = map[e].v;
				if (d[u] == d[v] + 1)//满足路径关系,注意逆向bfs时记录的最短路径,d[0]为最短路径,从起点开始,路径依次减一
				{
					min_color = min(min_color, map[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 = map[e].v;
				if (d[u] == d[v] + 1 && !vis[v] && map[e].c == min_color)//可能存在多个满足颜色条件的节点,细节问题注意前后路径关系
				{
					vis[v] = true;//控制访问条件,避免可能出现的重复访问的情况
					next2.push_back(v);
				}
			}
		}
		next = next2;
	}
	printf("%d\n", (int)ans.size());//最终输出的个数即为最终的最短路径
	for (int i = 0; i < ans.size(); i++)
	{
		if (i != ans.size() - 1)
			printf("%d ", ans[i]);
		else
			printf("%d\n", ans[i]);
	}
}
int main()
{
	int u, v, c;
	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);
			build(u - 1, v - 1, c);
			build(v - 1, u - 1, c);
		}
		re_bfs();//反向bfs寻找满足条件的路径
		bfs();
	}
	getchar();
	getchar();
	return 0;
}

1、首先理解几个数组设立的作用,g数组用于记录map中存储的位置关系的数组,存储位置关系时,注意所有连通关系一起处理,g数组则是用于记录节点为u时,存在几个对应关系,在map数组里处在什么位置
2、本题重要思想,反向bfs方法,注意此处理解,因为本题求解的最短路径,因为正向bfs寻找最小权值的点,无法保证得到的路径为最短路径,反向bfs则是始终保证最终d[0]所求的路径为最短路径,正向bfs时则每移动一步,步数减一

3、正向bfs时,注意权值大小比较的控制,当满足最短路径要求时,将所有的点进行颜色的比较,满足两者要求才将相应节点放入数组重新bfs寻找
4、易错点注意路径的控制,正向bfs时,路径应该是前一节点比后一节点大一,路径依次减一,注意路径控制的细节,想清楚

5、节点存储时,注意正反存储,图论问题解决时注意节点之间关系的存储
6、此题还有一巧妙之处,将字典序输出转换为颜色权值的比较,每个层次的节点依次输出权值最小的点,保证最后结果的字典序最小

7、图论中最短路径的问题,注意反向bfs用于确定最短路径的思路,重点理解反向bfs的思想

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值