POJ 1094 (拓扑排序)

这道题在我看来之所以采用拓扑排序,是因为数据所构成的图中存在环,而拓扑排序正好能巧妙解决这个问题,
再谈谈这个题的思想:


将两个节点构成的边存入一个图中,并且记录每一个节点的入度,进行拓扑排序:
将入度为0的节点先加入队列中,如果队列中节点数大于一,则说明存在节点无法判断其大小关系,取队首节点,并将该节点压入vector中,(因为要计算最后结果),删除队首节点,并删除与该节点相连接的节点所构成得边,如果删除之后相连接的节点的入度也变为0,则加入队列中。如此往复直至最后变为空队列,如果此时vector中的节点个数小于总的节点个数,则说明存在环。(因为如果存在环,则环中的元素永远也不可能入度==0)

实现代码:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <vector>

using namespace std;

int graph[30][30];
int in[30];
vector<int> v;

int topsort(int n){
    queue<int> q;
    v.clear();
    //因为之后还要计算,所以将in数组中的元素先存放的另一个数组中
    int tmp[30];
    for(int i=0;i<n;i++)
        tmp[i]=in[i];
    for(int i=0;i<n;i++){
        if(in[i]==0) q.push(i);
    }
    int flag=0;
    while(!q.empty()){
        if(q.size()>1) flag=1;
        int t=q.front();
        q.pop();
        v.push_back(t);
        for(int i=0;i<n;i++){
            if(graph[t][i]){
                tmp[i]--;
                if(tmp[i]==0) q.push(i);
            }
        }
    }
    if(v.size()<n) return 0;  //有环
    if(flag) return 1; //不能判断。
    return 2;
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF,n,m){
        memset(graph,0,sizeof(graph));
        memset(in,0,sizeof(in));
        int flag=0;char a,b,c;
        for(int i=1;i<=m;i++){
            scanf(" %c%c%c",&a,&b,&c);
            if(flag) continue;
            in[c-'A']++;
            graph[a-'A'][c-'A']=1;
            int t=topsort(n);
            if(t==2){
                printf("Sorted sequence determined after %d relations: ",i);
                for(int i=0;i<n;i++)
                    printf("%c",'A'+v[i]);
                printf(".\n");
                flag=1;
            }
            if(t==0){
                printf("Inconsistency found after %d relations.\n",i);
                flag=1;
            }
        }
        if(flag==0){
            printf("Sorted sequence cannot be determined.\n");
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值