-
有向无环图描述表达式
-
1.表达式转换为树
根是*
,右子树是((a+b)*(b*(c+d)) + (c+d)*e)
,左子树是((c+d)*e)
,以此类推。
-
2.有向无环图(DAG)描述表达式
- 合并方法
-
拓扑排序
存在回路的图没法拓扑排序
- 拓扑排序算法实现(贪心策略)
LeetCode 210. Course Schedule II
//时间复杂度:O(V+E)
class Solution {
public:
vector<int> greedy(vector<vector<int>> &od, vector<int> &id) {
stack<int> stack;//存放度为0的结点
vector<int> res;//保存拓扑排序结果
for (int i = 0; i < id.size(); ++i) {
if (!id[i]) {//如果节点i的入度为0
stack.push(i);//压入栈
}
}
while (!stack.empty()) {
int v = stack.top();
stack.pop();
res.push_back(v);
for (int &i : od[v]) {
id[i]--;//使节点v的邻接节点的入度都减少一
if (!id[i]) {//如果v的邻接节点的入度为0
stack.push(i);
}
}
}
return res.size() == id.size() ? res : vector<int>();
}
vector<int> findOrder(int numCourses, vector<vector<int>> &prerequisites) {
vector<int> id(numCourses, 0);//存放度的数组,初始化为0
vector<vector<int>> od(numCourses);//前驱:后驱
for (int i = 0; i < prerequisites.size(); ++i) {
id[prerequisites[i][0]]++;//更新结点的度
od[prerequisites[i][1]].push_back(prerequisites[i][0]);//b[i],a[i]...a[s]
}
return greedy(od, id);
}
};
- 拓扑排序算法实现(DFS)
class Solution {
public:
bool dfs_improve(int v,vector<vector<int>>&od,vector<int>&visited,vector<int>&loopvisited,stack<int>&st){
visited[v]=1;//标记访问过的节点,到一个点,标记一个点
for(int &i:od[v]){
if(!loopvisited[i]&&visited[i])return true;//如果loopvisited没有标记为访问,但visited却标记为访问了,表示这个节点在本次深度优先搜索时已经访问过,即存在环路。
if(!visited[i]){
bool loopcheck=dfs_improve(i,od,visited,loopvisited,st);
if(loopcheck)return true;
}
}
loopvisited[v]=1;//标记访问过的节点,但到整个深度优先搜索结束后才标记,所以loopvisited已作标记的是之前本次搜索之前就访问过的节点。
st.push(v);
return false;
}
vector<int> findOrder(int nc, vector<vector<int>> &pre) {
vector<int>visited(nc,0);//访问标记
vector<int>loopvisited(nc,0);//环路检测访问标记
vector<vector<int>>od(nc);//每个点的邻接点集
stack<int>st;//辅助栈
for(int i=0;i<(int)pre.size();i++){
od[pre[i][1]].push_back(pre[i][0]);
}
vector<int>res;//用于保存拓扑排序
bool hasloop=false;//是否存在环路
for(int i=0;i<nc;i++){
if(0==visited[i]){
if(dfs_improve(i,od,visited,loopvisited,st))hasloop=true;//DFS(改良)
}
}
if(hasloop)return res;//如果存在环路,返回空集
while(!st.empty()){//构造拓扑排序
res.push_back(st.top());
st.pop();
}
return res;
}
};
- 思考:逆拓扑排序该如何实现呢?
- 关键路径和关键活动
- 步骤如下