【PAT甲级 拓扑排序(假的) C++】1146 Topological Order (25 分)

拓扑排序的性质大约是:

  • 在未加入拓扑排序序列的顶点中,入度为0的顶点全都属于拓扑排序序列,在入度为0的顶点加入拓扑序列后,要删去从它出去的边使得其邻接点的入度-1,这样就会产生新的入度为0的顶点了。

所以这题其实就是一道模拟,模拟拓扑排序的过程,因为拓扑排序时,每次加入序列的都是入度为0的顶点,所以只需按照给定的拓扑排序序列的顺序模拟拓扑排序:

  • 如果遍历发现给定序列中的顶点的入度为0,那就模拟删边使得当前顶点的所有邻接点的入度-1;若不是0,那说明给定序列不是拓扑序列。

所以解法就是:顺序遍历要检验的序列,跟着序列的顺序判断当前顶点入度是否为0,为0就说明其确实在拓扑序列中,于是使得其邻接点的入度-1;不为0说明当前序列不是拓扑序列,不需要再判断其他的顶点了。


邻接表

# include <iostream>
# include <vector>
# include <queue>
# include <algorithm>
using namespace std;

int N, M;
vector<int> G[1001];
vector<int> inDegree(1001);
vector<int> inDegree_copy(1001);

int main() {
    
    
    cin >> N >> M;
    for(int i = 0;i < M;++i){
    
    
        int u, v;
        cin >> u >> v;
        G[u].push_back(v);
        inDegree_copy[v]++;
    }

    int K;
    cin >> K;
    vector<int> indices; // 装答案
    for(int i = 0;i < K;++i){
    
    
        inDegree = inDegree_copy;
        int flag = 1;
        for(int j = 0;j < N;++j){
    
    
            int query;
            cin >> query;
            if(flag == 0) continue; // flag=0,说明这个序列已经不是拓扑序列了,不需要再检验其他顶点了,只需完成输入即可
            if(inDegree[query] == 0) // 如果入度为0,说明,query是在拓扑排序的正确位置
                for(int v: G[query]) // 删掉当前顶点和其出去的边,让其邻接点的入度-1
                    inDegree[v]--; 
            else 
                flag = 0; // 标明是错误答案
           
        }
        if(flag == 0) indices.push_back(i);
    }

    for(int i = 0;i < indices.size();++i){
    
    
        cout << indices[i];
        i != indices.size() - 1 ? cout << " " : cout << endl;
    }
    
    return 0;
}



邻接矩阵

# include <iostream>
# include <vector>
# include <queue>
# include <algorithm>

using namespace std;

const int INF = 0xffffff;

int N, M;
bool G[1001][1001] = {
    
    false};
vector<int> inDegree(1001);
vector<int> inDegree_copy(1001);


int main() {
    
    
    cin >> N >> M;
    for(int i = 0;i < M;++i){
    
    
        int u, v;
        cin >> u >> v;
        G[u][v] = true;
        inDegree_copy[v]++;
    }

    int K;
    cin >> K;
    vector<int> indices; // 装答案
    for(int i = 0;i < K;++i){
    
    
        inDegree = inDegree_copy;
        int flag = 1;
        for(int j = 0;j < N;++j){
    
    
            int query;
            cin >> query;
            if(flag == 0) continue; // flag=0,说明这个序列已经不是拓扑序列了,不需要再检验其他顶点了,只需完成输入即可
            if(inDegree[query] == 0){
    
     // 如果入度为0,说明,query是在拓扑排序的正确位置
                for(int v = 1;v <= N;++v) // 删掉当前顶点和其出去的边,让其邻接点的入度-1
                    if(G[query][v] == true)
                        inDegree[v]--; 
            } else {
    
     // 如果入度不为0,说明query不在拓扑排序的正确位置,当前序列不是拓扑序列,标记为错误答案
                // 因为这个是一个一个地输入顶点,而不是一次输入一整个检验序列,所以不能break,要循环直到本轮输入完成
                flag = 0; // 标明是错误答案         // break;
            }
        }
        
        if(flag == 0) indices.push_back(i);
    }

    for(int i = 0;i < indices.size();++i){
    
    
        cout << indices[i];
        if(i != indices.size() - 1)
            cout << " ";
        else
            cout << endl;
    }
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/MYMarcoreus/article/details/113868533