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

该博客主要讨论了如何验证给定的顶点序列是否符合拓扑排序的性质。通过模拟拓扑排序过程,检查每个顶点的入度是否为0,并在适当的时候更新邻接节点的入度。如果序列中的所有顶点都能按顺序满足条件,则序列是有效的拓扑排序,否则不是。算法使用了邻接表和邻接矩阵两种数据结构进行实现。
摘要由CSDN通过智能技术生成

拓扑排序的性质大约是:

  • 在未加入拓扑排序序列的顶点中,入度为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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值