uva 1599
来源:互联网 发布:win10网络授权 编辑:程序博客网 时间:2024/06/05 00:24
原题
最近课业比较繁忙, 好久没时间写题了。
这也算是最短路径问题的改版,求满足一个条件的最短路径。
经验不足,一开始自然就想到用DFS(因为比较好写),结果当然TLE了
后来才想起来DFS的复杂度是O(N^2), 而BFS是O(N+E),
所以遇到这种规模比较大的图肯定要用BFS了, 根本不是一个数量级啊
网上虽然方法比较多, 但是描述得不是很全面, 我再来整理一下吧
主要思路是用两次BFS, 比较巧妙
第一次逆向BFS(从终点出发)找出终点到所有点的距离并标记, 比较简单就不赘述了
第二次BFS是关键, 从起点出发, 首先要知道下一次走的点应该是那些与终点距离只比起点少1的点, 只有这样才能保证走的都是最短路径.
每到一个点, 关键就是用一个点集nextVertices来存储下一步能走的所有点之中边权最小的点(而不是单独的一个变量表示当前的点, 就相当于多路同步进行),
我是先遍历一边所有可能走的边找出最小边权MinColor, 然后再遍历以便找出边权等于MinColor的点, 就放进下一轮要选择走的点集nextVertices内
这里需要注意的一个小细节, 刚要开始第二次BFS的时候, 只把起点放入nextVertices就能开始上述循环了
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>#include <string>#include <vector>#include <set>#include <stack>#include <queue>#include <deque>#include <map>#include <list>#include <cassert>#include <iomanip>using namespace std;const int MAXN = 200000+1; const int INF = 1000000000 + 10;typedef long long LL;/*uva 1599关键 : 0. 用BFS而不用DFS的原因是在结点较多的情况下BFS(O(V+E))更快 1. 第一次倒着BFS找到终点到其余各点的最短路径长度, [关键难点]第二次正向BFS从中找到到达终点的最短路径 2. 第二次如果有color值相同的边如何确定下一个点? 解决方法 : 先从与当前点邻接的边中找出所有边最小的color值 min_color, 之后再遍历容器内的边, 找出color值等于min_color的所有边, 保存这些边指向的顶点, 这些顶点即为下一轮需要BFS的顶点 */map<int, map<int,int> > G; // 无向网图 int M, N;bool isVisited[MAXN];int Distance[MAXN]; // 记录各个点到终点的距离 typedef map<int,int>::iterator MPIT;//bool Lessthan(int * path1, int * path2){ while( *path1++ == *path2++ ); return *path1 < *path2;}void BFS_first(){ queue<int> Q; Q.push(N); int dis = 0; Distance[N] = 0; while( !Q.empty() ){ int cur = Q.front(); Q.pop(); MPIT it = G[cur].begin(); while( it!=G[cur].end() ){ if( !Distance[it->first] && it->first!=N ){ Distance[it->first] = Distance[cur]+1; Q.push(it->first); } it++; } }// for(int i=1; i<=N; i++) std::cout << Distance[i] << " " << endl;}void BFS_second(){ vector<int> ans, nextVertices; MPIT it; int cur; memset(isVisited, 0, sizeof(isVisited)); nextVertices.push_back(1); isVisited[1] = true; for(int i=0; i<Distance[1];i++ ){ int min_color = INF; for(int j=0; j<nextVertices.size(); j++){ cur = nextVertices[j]; it = G[cur].begin(); while( it!=G[cur].end() ){ if(Distance[cur]-1 == Distance[it->first] && G[cur][it->first] < min_color ){ min_color = G[cur][it->first]; } it++; } } ans.push_back(min_color); vector<int> tmpNext; for(int i=0; i<nextVertices.size(); i++){ cur = nextVertices[i]; it = G[cur].begin(); while( it!=G[cur].end() ){ if( !isVisited[it->first] && Distance[cur]-1 == Distance[it->first] && G[cur][it->first] == min_color ){ isVisited[it->first] = true; min_color = G[cur][it->first]; tmpNext.push_back(it->first); } it++; } } nextVertices = tmpNext; } cout << ans.size() << endl; for(int i=0; i<ans.size()-1; i++) cout << ans[i] << " "; cout << ans[ans.size()-1] << endl;}int main(){// freopen("input2.txt","r",stdin); while( cin >> N >> M ){ int a, b, c; G.clear(); memset(Distance, 0, sizeof(Distance)); for(int i=0; i<M; i++){ cin >> a >> b >> c; if( G[a][b]==0 || c < G[a][b] ){ // 当没有加过边或者准备要加的边更短就更新边 G[a][b] = G[b][a] = c; } } BFS_first(); BFS_second(); } return 0;}
0 0
- uva 1599
- uva UVA - 1599 Ideal Path
- uva 1599 - Ideal Path
- UVa 1599 Ideal Path
- Uva - 1599 - Ideal Path
- UVa 1599 Ideal Path
- UVa 1599 Ideal Path
- UVA 1599 Ideal Path
- UVA 1599 理想路径
- uva
- UVA
- UVA
- UVA
- uva
- UVA
- UVA
- UVA
- UVA
- 黑马程序员——网络概念及Socket编程示例
- 安卓 线程 和 线程池
- LeetCode -- Length of last word
- Linux-grep学习笔记
- LeetCode -- Majority Element II
- uva 1599
- poj 2533 Longest Ordered Subsequence (最长上升子序列)
- LeetCode -- Nim Game
- Show Line Numbers显示行号问题
- 超实用的JavaScript代码段 Item4 --发送短信验证码
- 阅读开源项目源代码的方法
- 小米开源便签Notes-源码研究(0)-整体功能介绍(图文并茂)
- java 的 Thread_wait、notify、notifyAll的使用方法
- 私家菜谱version1.0即将发布,暂时只提供【iOS】