• 算法之拓扑排序


      拓扑排序就是把有向无环图变成一种线性的序列,这种线性序列有前后关系。如果用队列来存储最后的结果,如果队列中的数据与总的数据n不相等,则说明有环。

      此拓扑排序的思想是:

      (1)从有向图中选取一个没有前驱的顶点,并输出之;

      (2)从有向图中删去此顶点以及所有以它为尾的弧;

      (3)如果入度没有为0的表示有环,这时候如果还是向遍历,可以自己加一个起点,然后连接到任意一个图节点即可。

      拓扑排序简易代码:

      

    queue<int>q;
    //priority_queue<int,vector<int>,greater<int>>q;
    //优先队列的话,会按照数值大小有顺序的输出
    //此处为了理解,暂时就用简单队列
    TopoSort()
    {
        for(inti=1;i<=n;i++)
        {
            if(indegree[i]==0)
            {
                q.push(i);
            }
        }
     
        inttemp;
        while(!q.empty())
        {
            temp=q.front();//如果是优先队列,这里可以是top()
            printf("%d->",temp);
            q.pop();
            for(inti=1;i<=n;i++)//遍历从temp出发的每一条边,入度--
            {
                if(map[temp][i])
                {
                    indegree[i]--;
                    if(indegree[i]==0)q.push(i);
                }
            }
        }
    }

      hdu今天竟然关闭了,只能自己先随便写写了:

    使用了数组存储图的信息:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<iterator>
    using namespace std;
    int Map[100][100];
    int indegree[100];
    queue<int> resq;
    void TopoSort(int n)
    {
        queue<int> temq;
        while(!resq.empty())
        {
            resq.pop();
        }
        for(int i=0;i<n;++i)
        {
            if(indegree[i]==0)
            {
                temq.push(i);
            }
        }
    
        while(!temq.empty())
        {
            int temp = temq.front();
            temq.pop();
            ++cnt;
            resq.push(temp);
            for(int i=0;i<n;++i)
            {
                if(Map[temp][i])
                {
                    --indegree[i];
                    if(indegree[i]==0)
                    {
                        temq.push(i);
                    }
                }
            }
        }
    
    }
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            memset(Map,0,sizeof(Map));
            memset(indegree,0,sizeof(indegree));
            for(int i=0;i<m;++i)
            {
                int a1,a2;
                scanf("%d%d",&a1,&a2);
                if(Map[a1][a2]==0)
                {
                    Map[a1][a2] = 1;
                    ++indegree[a2];
                }
            }
            printf("answer:
    ");
            TopoSort(n);
            while(!resq.empty())
            {
                int a = resq.front();
                resq.pop();
                printf("%d ",a);
            }
            printf("
    ");
        }
        return 0;
    }
    /*
    5 4
    0 1
    1 2
    1 4
    3 1
    */
    View Code

     hdu1285,它拓扑的时候还要从小到大排序。有一个输入也是坑,有重复数据。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<vector>
    using namespace std;
    int Map[501][501];
    int indegree[501];
    queue<int> qi;
    
    void TopoSort(int n)
    {
        //优先队列
        priority_queue<int,vector<int>,greater<int> > q;
        for(int i=1;i<=n;++i)
        {
            if(indegree[i]==0)
                q.push(i);
        }
        while(!q.empty())
        {
           int top = q.top();
           q.pop();
           qi.push(top);
           for(int i=1;i<=n;++i)
             if(Map[top][i])
            {
                --indegree[i];
                if(indegree[i]==0)
                    q.push(i);
            }
        }
    }
    
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            memset(Map,0,sizeof(Map));
            memset(indegree,0,sizeof(indegree));
            for(int i=0;i<m;++i)
            {
                int win,lose;
                scanf("%d%d",&win,&lose);
                //不加会报错,测试数据会有重复!!!
                if(Map[win][lose]==0)
                {
                    Map[win][lose] = 1;
                    ++indegree[lose];
                }
                
            }
            TopoSort(n);
            while(!qi.empty())
            {
                printf("%d",qi.front());
                qi.pop();
                if(!qi.empty())
                    printf(" ");
            }
            printf("
    ");
        }
        return 0;
    }
    View Code

    hdu2647

    此题的map不能使用数组,不然内存会过不去,使用vector。拓扑顺序跟输入相反。

    这次测试数据没有重复数据,并且需要判断是否有环。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<map>
    using namespace std;
    
    vector<int> Map[10001];
    int indegree[10001];
    int tcost;
    map<int,int> mii;
    
    void init()
    {
        for(int i=0;i<=10000;++i)
            Map[i].clear();
        memset(indegree,0,sizeof(indegree));
        tcost = 0;
        mii.clear();
    }
    
    void TopoSort(int n)
    {
        //暂时,结果队列
        queue<int> qt,qr;
        int len,nextlen,price;
        len = nextlen = 0;
        price = 888;
        for(int i=1;i<=n;++i)
            if(indegree[i]==0)
            {
                qt.push(i);
                tcost += price;
                ++len;
            }
        ++price;
        while(!qt.empty())
        {
            int top = qt.front();
            qt.pop();
            qr.push(top);
            --len;
            for(int i=0;i<Map[top].size();++i)
            {
                --indegree[Map[top][i]];
                if(indegree[Map[top][i]]==0)
                {
                    ++nextlen;
                    tcost += price;
                    qt.push(Map[top][i]);
                }
            }
            if(len == 0)
            {
                len = nextlen;
                nextlen = 0;
                ++price;
            }
        }
        if(qr.size()!=n)
        {
            tcost = -1;
        }
    }
    
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            init();
            for(int i=0;i<m;++i)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                //反向
                pair<map<int,int>::iterator,bool> mib = mii.insert(pair<int,int>(a+10000*b,a));
                //去重复数据,虽然测试数据没有重复数据
                if(mib.second)
                {
                    ++indegree[a];
                    Map[b].push_back(a);
                }
            }
            TopoSort(n);
            printf("%d
    ",tcost);
        }
        return 0;
    }
    View Code

    hdu3342,标准拓扑排序题,很简单,判断是否有环就行了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    
    int Map[101][101];
    int indegree[101];
    
    void TopoSort(int n)
    {
        queue<int> qtemp,qres;
        for(int i=0;i<n;++i)
            if(indegree[i]==0)
                qtemp.push(i);
        while(!qtemp.empty())
        {
            int top = qtemp.front();
            qtemp.pop();
            qres.push(top);
            for(int i=0;i<n;++i)
                if(Map[top][i])
                {
                    --indegree[i];
                    if(indegree[i]==0)
                        qtemp.push(i);
                }
        }
        if(qres.size()==n)
            printf("YES
    ");
        else    printf("NO
    ");
    }
    
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m),n)
        {
            memset(Map,0,sizeof(Map));
            memset(indegree,0,sizeof(indegree));
            for(int i=0;i<m;++i)
            {
                int mas,pre;
                scanf("%d%d",&mas,&pre);
                if(Map[mas][pre]==0)
                {
                    Map[mas][pre] = 1;
                    ++indegree[pre];
                }
            }
            TopoSort(n);
        }
        return 0;
    }
    View Code

    hdu4857,这道题目比较坑的是一个数据:

    1

    3 1

    3 1

    答案是3 1 2,而我输出2 3 1。

    因此需要逆序拓扑。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<stack>
    #include<map>
    using namespace std;
    
    vector<int> vi[30001];
    int indegree[30001];
    map<int,int> mii;
    
    void init(int n)
    {
        for(int i=0;i<=n;++i)
            vi[i].clear();
        memset(indegree,0,sizeof(indegree));
        mii.clear();
    }
    
    void TopoSort(int n)
    {
        priority_queue<int,vector<int>,less<int> > qtemp;
        stack<int> si;
        int cnt = 0;
        for(int i=1;i<=n;++i)
            if(indegree[i]==0)
            {
                qtemp.push(i);
            }
        while(!qtemp.empty())
        {
            int top = qtemp.top();
            qtemp.pop();
            si.push(top);
            int iSize = vi[top].size();
            for(int i=0;i<iSize;++i)
            {
                int data = vi[top][i];
                --indegree[data];
                if(indegree[data]==0)
                    qtemp.push(data);
            }
        }
        while(!si.empty())
        {
            printf("%d",si.top());
            si.pop();
            if(!si.empty()) printf(" ");
        }
        printf("
    ");
    }
    int main()
    {
        int t,n,m;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            init(n);
            for(int i=0;i<m;++i)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                pair<map<int,int>::iterator,bool> pmb = mii.insert(pair<int,int>(a*30000+b,a));
                if(pmb.second)
                {
                    vi[b].push_back(a);
                    ++indegree[a];
                }
            }
            TopoSort(n);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    第五周
    第四周
    第三周作业
    第二周编程总结
    编程总结(3)
    编程总结(2)
    编程总结(1)
    第七周作业
    第六周作业
    第五周作业
  • 原文地址:https://www.cnblogs.com/jlyg/p/7233027.html
Copyright © 2020-2023  润新知