欧拉路径 LeetCode 332

来源:互联网 发布:女程序员 编辑:程序博客网 时间:2024/05/13 03:20

欧拉路径是图中这样一条路径,包含了所有边,且只包含一次。如果起点和终点是同一个点,则是一种特殊的欧拉路径——欧拉环路。


求法1:暴力法:遍历所有的路径,如果当前路径长度为总边数,则当前路径是一条欧拉路径,如果一直没有碰到这样的路径,则无解。

一个图总共多少条路径(一般是有环的)

1)不允许路径里有环,也就是路径里的点都只出现一次的,|V|!(第一个点|V|种选择,第二个|V| - 1种。。 n * (n - 1) ...

2)  路径里每条边只能用一次,但是顶点可以出现多次。|E|!


欧拉路径是第2种路径。

区别就是判重的 inPath用的是点还是边的问题

总结一下:

1)普通的 顶点遍历 mark vertex 后不会unmark, O(|V|)

2)路径遍历, inPath mark X,退出后unmark  X, O(|X|!), 其中,对于基于点的路径 X= V,基于边的路径 X= E,


第二种遍历和全排列类似,其实搜索的已经不是原来的graph,状态定义不是vertex,而是路径,是一个新的隐式图,和全排列的隐式图一样,是一棵树。


class Solution {public:    vector<string> findItinerary(vector<pair<string, string>> tickets) {        unordered_map<string, unordered_map<string, int>> G;        for (auto &ticket : tickets) {            G[ticket.first][ticket.second] += 1;        }        vector<string> path;        vector<vector<string>> ans;        function<void(string, int)> dfs = [&](string v, int n) {            if (n == tickets.size()) {                ans.push_back(path);            }            else {                for (auto &e : G[v]) {                    if (e.second > 0) {                        e.second -= 1;                        path.push_back(e.first);                        dfs(e.first, n + 1);                        e.second += 1;                        path.pop_back();                    }                }            }        };        path.push_back("JFK");        dfs("JFK", 0);        sort(ans.begin(), ans.end());        return ans[0];    }    };


方法2:Hierholzer's algorithm 有点象拓扑排序的“基于边”的版本

前提是先确定确实存在欧拉路径,根据顶点的度数。

存在欧拉回路和欧拉路径的判断:
1)欧拉回路:
无向图:每个顶点的度数都是偶数,则存在欧拉回路。
有向图:每个顶点的入度都等于出度,则存在欧拉回路。
2)欧拉路径:
无向图:当且仅当该图所有顶点的度数为偶数 或者 除了两个度数为奇数外其余的全是偶数。
有向图:当且仅当该图所有顶点 出度=入度 或者 一个顶点 出度=入度+1,另一个顶点 入度=出度+1,其 他顶点 出度=入度。


然后用Hierholzer算法:

class Solution {public:    vector<string> findItinerary(vector<pair<string, string>> tickets) {        unordered_map<string, priority_queue<string, vector<string>, greater<string>>> G;        for (auto &ticket : tickets) {            G[ticket.first].push(ticket.second);        }                vector<string> path;        function<void(string)> dfs = [&](string v) {                auto & edges = G[v];                while (edges.size() > 0) {                    string to = edges.top(); edges.pop();//这里把边从邻接表里删去就是相当于mark这条边。                    dfs(to);                }                path.push_back(v);        };                dfs("JFK");        reverse(path.begin(), path.end());        return path;    }    };




0 0