UVA - 10305 --- 拓扑排序

题目链接:https://vjudge.net/problem/UVA-10305#author=acmparand

题目:就是裸的输出拓扑序列

算法介绍:

几个术语:(参考《大话数据结构 第七章 图 7.8 拓扑排序)

AOV网(Activity On Vertex Network):用一个图表示一个工程前后执行顺序(又如:各个课程之间的选修次序),用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图即为AOV网

拓扑序列:设G=(V, E)是一个具有n个顶点的有向图,V中的顶点序列v1、v2,.....,vn;满足若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必在顶点vj之前,这样的序列就是一个拓扑序列。

(上面的定义,emmm,很正式,其实直观上理解,就是你找出一个序列,你按照这个序列进行工作或者学习,不存在障碍,拿课程选修来说,就是你找出一个序列,你按照这个序列顺序学习,不会遇到一门课,你还没学它的先修课就开始学它了,那样你肯定学的一脸懵逼是吧~~)理解之后,你会发现,拓扑排序在现实工程中还是很有用的,可以避免很多等待的时间成本,提高效率。

拓扑排序:其实就是对一个有向图构造拓扑序列的过程。

其中,如果构造完毕后,发现还存在图中的顶点不在这个序列中(哪怕只有一个),那么可以肯定,这个网存在环(回路),不是AOV网。

算法思想:

1.  从图中选择一个入度为0的顶点输出到拓扑序列

2. 从图中删除此顶点,并删除以此顶点的弧

3. 重复1、2操作,直到输出图中所有顶点或者AOV网不存在入度为0的顶点

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin             freopen("in.txt","r",stdin)
#define Fout            freopen("out.txt","w",stdout)
#define random(a,b)    a+rand()%(b-a+1)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 1e3 + 50;
const int INFint = 0xffffff;
const ll INFll = (ll)1e18;

#ifndef ONLINE_JUDGE

#endif // ONLINE_JUDGE

inline int readint(){
    int sgn = 1; int sum = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if(ch == '-')   sgn = -sgn;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9') {
        sum = sum*10+(ch-'0');
        ch = getchar();
    }
    return sgn*sum;
}

inline ll readll(){
    ll sgn = 1; ll sum = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if(ch == '-')   sgn = -sgn;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9') {
        sum = sum*10+(ch-'0');
        ch = getchar();
    }
    return sgn*sum;
}

int n, m;
int cnt[maxn];      //每个顶点的入度
vector<int> v[maxn];    //邻接表


void init(){
    memset(cnt, 0, sizeof(cnt));
    for(int i = 0; i < maxn; ++i){
        v[i].clear();
    }
}

void solve(){
    while(scanf("%d%d", &n, &m) == 2){
        if(!n && !m)    break;
        init();
        for(int i = 0; i < m; ++i){
            int u = readint();      // 边的起点
            int w = readint();      // 边顶点终点
            v[u].push_back(w);      // 建边
            cnt[w]++;               // 终点的入度加1
        }
        vector<int> ans;            // 记录弹出栈的数字,即最终的拓扑序列
        stack<int> st;              // 存放入度为0的顶点
        for(int i = 1; i <= n; ++i){    // 初始时,遍历放入入度为0的顶点
            if(cnt[i] == 0)
                st.push(i);
        }
        while(!st.empty()){         // 直到栈为空
            int now = st.top();     // 当前的顶点
            st.pop();               // 从图中删除该顶点 需要更新与此顶点相连的顶点的入度
            ans.push_back(now);
            // 遍历该顶点的所有边的另一端顶点, 将另一端的顶点的入度减1
            int Size = v[now].size();
            for(int i = 0; i < Size; ++i){
                int tmp = v[now][i];
                cnt[tmp]--;
                if(cnt[tmp] == 0)   // 当顶点的入度为0时,入栈
                    st.push(tmp);
            }
        }
        int Size = ans.size();      // 输出该拓扑序列
        for(int i = 0; i < Size; ++i){
            printf("%d", ans[i]);
            if(i != Size - 1)   printf(" ");
        }
        printf("\n");
    }
}


int main()
{
    solve();
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值