poj1094

来源:互联网 发布:网络推广服务 编辑:程序博客网 时间:2024/05/28 05:15

一个定义:对一个DAG(无环有向图)进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。

1.本题顺序:

a.先判有没有环,有环就直接输出不能确定;(有两种情况,一种是,直接判断反向边,肯定就有环了,第二种情况是,生成的拓扑序内含字母个数小于题目中给出的字母的个数)

b.如果没有环,那么就看会不会有多种情况,如果有多种情况就再读下一行;如果全部行读完还是有多种情况,就是确定不了

c.如果最后没有环,也不存在多种情况(即每次取出来入度为零的点只有一个),那么才是答案

2.有答案就先出答案,不管后面的会不会矛盾什么的
3.如果在没有读完所有输入就能出答案,一定要把剩下的行都读完。

一开始没有往拓扑排序上面想,一开始想的是,找有向图的环。当然,方法很多了。

首先,可以采用如上的拓扑排序

第二,可以采用寻找SCC(Strongly Connected Component,即强连通分量)的方法来寻找,因为SCC的定义是,u->v, v->u,这正好是环的特征。至于强联通分量,可以采用Tarjan再或者是一个DFS就可以解决,貌似这样慢一些~(还不会写)

第三,可以采用改进的DFS,我们可以对DFS稍加变化,来解决这个问题。解决的方法如下:(更不会写了)

图中的一个节点,根据其C[N]的值,有三种状态:

0,此节点没有被访问过

-1,被访问过至少1次,其后代节点正在被访问中

1,其后代节点都被访问过。

按照这样的假设,当按照DFS进行搜索时,碰到一个节点时有三种可能:

1、如果C[V]=0,这是一个新的节点,不做处理

2、如果C[V]=-1,说明是在访问该节点的后代的过程中访问到该节点本身,则图中有环。

3、如果C[V]=1,类似于2的推导,没有环。    在程序中加上一些特殊的处理,即可以找出图中有几个环,并记录每个环的路径

P.s.:图论毕竟是数学,这才是正常的做题的节奏!

#include <iostream>
#include <stack>

using namespace std;

#define MAXN 27

int graph[MAXN][MAXN], indegree[MAXN], list[MAXN], in[MAXN];

int toposort(int n)
{
    memcpy(in, indegree, sizeof(indegree));
    stack<int> s;
    for (int i = 0; i < n; i++)
    {
        if (!in[i])//no indegree (that is to say the indegree of current node is zero)
            s.push(i);
    }
    int countt = 0;
    bool flag = false;
    while (!s.empty())
    {
    if (s.size()>1)
            flag = true;//inconsistency of the separate node, 'cuz there exist multiple ways of toposort.
        int temp = s.top();
        list[countt++] = temp;
        s.pop();
        for (int i = 0; i < n; i++)
        {
            if (graph[temp][i] && --in[i] == 0)//if the graph from temp to i is connected and the indegree is still 0 after minus
                //you may assume that first let's find the component of the graph who is connected from temp to i
                //then, minus itself by one, check if it's indegree is 0 or not.
                    s.push(i);
        }
    }
    if (countt != n) return 1;//there are a circle in di-graph.(So-called Inconsistency)
    else if (flag) return 2;//there are multiple solutions
    return 0;//finally there are solution only.
}

int main()
{
    int n, m;
    while (cin >> n >> m && (n || m))
    {
        bool flag = false, flag2 = false;
        memset(graph, 0sizeof(graph));
        memset(indegree, 0sizeof(indegree));
        for (int i = 1; i <= m; i++)
        {
            char a, b, waste;
            cin >> a >> waste >> b;
            if (!flag && !flag2)
            {
                if (graph[b - 'A'][a - 'A'] == 1)//reverse edge
                {
                    flag2 = true;
                    cout << "Inconsistency found after " << i << " relations." << endl;
                    continue;
                }
                if (graph[a - 'A'][b - 'A'] == 0)//disconnected
                {
                    graph[a - 'A'][b - 'A'] = 1;
                    indegree[b - 'A']++;//with one indegree of node b
                }

                int flag3 = toposort(n);
                if (flag3 == 0)
                {
                    cout << "Sorted sequence determined after " << i << " relations: ";
                    for (int j = 0; j < n; j++)
                        cout << (char)(list[j] + 'A');
                    cout << '.' << endl;
                    flag = true;
                }
                else if (flag3 == 1)
                {
                    cout << "Inconsistency found after " << i << " relations." << endl;
                    flag2 = true;
                }
            }
        }
        if (!flag && !flag2)
            cout << "Sorted sequence cannot be determined." << endl;
    }
}
这个代码是学习的别人的,必须要说明一下。