原题链接:332. 重新安排行程
solution:
有向图欧拉路径:
欧拉路径:经过每一条边一次,但是不要求回到起始点。
判断欧拉路径是否存在的方法
1.有向图 : 图连通,当且仅当该图所有顶点数的度数为0,或者一个顶点的度数为1,另一个顶点的度数为-1,其他顶点的度数为0.
2.无向图:图连通,当且仅当该图所有顶点的度数为偶数,或者除了两个度数为奇数外其余的全是偶数。
本题已经说明,一定有一条合法路径因此不需要判定是否有合法路径。下面以一张图表明什么是欧拉路径。
该图的遍历顺序是:A-B-C-B-D-B-F,当抵达F也就是终点的时候,又有没有出度就会把F存入res答案中,并返回B继续遍历,B-E-B,最后返回B后由于B的所有出度都已遍历完就开始回溯。因此最后res = F-B-E-B-D-B-C-B-A,最后将res颠倒顺序即可。
直接从起点开始dfs即可,每次选择一条没有遍历过的边,递归进行遍历。当把当前节点的所有出边都遍历完时,将该点加入路径序列。最终记录的路径是真正遍历路径的逆序,所以我们要将记录的路径逆序输出。题目中要求我们输出字典序最小的路径,直接贪心即可,每次优先选择字典序最小的出边进行遍历。这一步可以用堆或者平衡树来存储每个点的所有出边.
class Solution {
public:
unordered_map<string,multiset<string>> g; //存储有向图,同时可以起到去重和排序的作用
vector<string> res; //返回值
void dfs(string ver) {
while(g[ver].size()) {
auto next = *g[ver].begin(); //字典序最小的出路
g[ver].erase(g[ver].begin()); //走过就删除本条路径
dfs(next);
}
res.push_back(ver);
}
vector<string> findItinerary(vector<vector<string>>& tickets) {
for (auto &ticket : tickets) g[ticket[0]].insert(ticket[1]);
dfs("JFK");
reverse(res.begin(),res.end());
return res;
}
};