poj 1094 拓扑排序变形

题目链接:http://poj.org/problem?id=1094

题目大意就是给你两个数,前一个代表的是有几个字母要进行排序,后一个表示的是给你几个关系,对于这些关系,你要找出他们在第几个关系时确定了这些字母的顺序,或者说在第几个关系的时候出现了环,还有一种就是整个序列是没有唯一确定的关系的。

背景:一开始直接吓傻了,居然拓扑排序还能找出在什么时候确定的关系,什么时候出现的环啊orzzzzzzzz,想了一个多小时吧,我的思路一直停留在对其直接进行拓扑排序,从dfs想到bfs一直在思考如何找出在什么时候能判环或者确定整个序列。后来发现这样的话根本不可能吧orzzz,因为这个拓扑排序开始的时候就是所有关系已经存入的时候了,无法找出。

无奈之下只能去搜题解,发现这道题是巧妙的对于每个输入的关系时就进行一次包括当前关系以及之前所有关系的拓扑排序。

关键在于如果出现环了或者有了唯一确定的序列以后单纯的只读入之后的数据并不需要对其进行操作。如果还没有确定的关系的话就接着进行之后的拓扑排序。直到如果最后所有关系都读完了还是没有确定的关系,这时候才可以说整个序列不唯一。

大致的和之前的拓扑排序是一致的,就是判环和判断序列是否唯一,判环的话就是判断是否所有顶点都进入了队列之中,如果还有剩余的顶点就是有环的。

判断序列是否唯一的话就是,每次队列中有且仅有一个元素,如果有超过一个的元素,那么这个序列肯定是不唯一的。

如果这个序列是唯一的话还要保证所有顶点都进入了答案队列之中去,否则可能会出现第一个关系就被判定为确定了orzzzzzzzzzz 因为这个调试了好久。。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
#define M 10000
int indegree[M];
vector<int> G[M];
int mark[27];
int n,m;
queue<int> p;
int toposort()
{
    while(!p.empty())  //清空队列
        p.pop();
    queue<int> q;
    int flag = 1;
    int temp[27];
    int num = 0;
    for(int i = 0;i < 26;i++)
    {
        if(mark[i])  //存在的顶点才记录
        {
            num++; //记录顶点的个数
            temp[i] = indegree[i];
            if(temp[i]==0)
            q.push(i);
        }
    }
    //cout << "front debug " << num << endl;
    while(!q.empty())
    {
        num--;
        if(q.size()>1)
            flag = 0; //此时并不能直接return 因为有可能有环
        int cur = q.front();
        q.pop();
        p.push(cur);
        for(int i = 0;i < G[cur].size();i++)
        {
            //cout << "debug " << G[cur][i];
            temp[G[cur][i]]--;
            if(temp[G[cur][i]]==0)
            {
                q.push(G[cur][i]);
            }
        }
    }
    if(num>0) return -1;  //如果还有剩余的顶点那么就是有环
    //cout << "this is debug" << p.size() << endl;
    if(p.size()==n && flag==1) return 1;//确定  //得到的答案的字母个数与所给的一致并且有序
    //必须要保证所有顶点都在答案队列中才可能是确定的
    //cout << "debug " << num << endl;
    return 0;
}
int main()
{
    while(cin >> n >> m)
    {
        if(n==0 && m==0) break;
        memset(mark,0,sizeof(mark));
        memset(indegree,0,sizeof(indegree));
        for(int i = 0;i < 26;i++)
            G[i].clear();
        int num = 0;
        int sign = 0;
        for(int i = 0;i < m;i++)
        {
            char s[5];
            cin >> s;
            if(sign) continue;
            if(mark[s[0]-'A']==0)
                mark[s[0]-'A'] = 1; //对顶点进行标记
            if(mark[s[2]-'A']==0)
                mark[s[2]-'A'] = 1;
            indegree[s[2]-'A']++;
            G[s[0]-'A'].push_back(s[2]-'A');
            int ans = toposort();
            if(ans == -1)//有环
            {
                printf("Inconsistency found after %d relations.\n",i+1);
                sign = 1;
            }
            if(ans == 1) //确定
            {
                printf("Sorted sequence determined after %d relations: ",i+1);
                while(!p.empty())
                {
                    int temp = p.front();
                    p.pop();
                    printf("%c",temp+'A');
                }
                printf(".\n");
                sign = 1;     //已经出现了明确的关系
            }
        }
        if(!sign)
        {
            printf("Sorted sequence cannot be determined.\n");
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值