zoukankan      html  css  js  c++  java
  • 拓扑排序 学习笔记

    拓扑排序适用于DAG(有向无环图)。它可以按照一定的遍历顺序将点重新排列,能减少算法的复杂度。

    先要记录点的入度,将入度为0的点入列,然后与它相邻的点in[]--。如果已经为0,入列,以此类推。在遍历的同时将点按照遍历的顺序记录下来即可。

    代码:

     while(!q.empty())
        {
            int now=q.front();q.pop();
            pos[++cnt]=now;
            for (int i=head[now];i;i=edge[i].next)
            {
                int to=edge[i].to;
                in[to]--;
                if (!in[to]) q.push(to);
            }
        }

    下面是几道拓扑排序的题。

    T1 小叶子的故事之写代码

    题目大意:有N个数。给M个关系(x,y),表示x必须在y之前。输出字典序最小的数列。

    ---------------------------------------------------------------------------------

    拓扑排序裸题,只要用小根堆维护点的顺序即可。

    #include<bits/stdc++.h>
    using namespace std;
    int in[100005],ans[100005],vis[100005];
    int n,m,u,to,jishu;
    priority_queue<int,vector<int>,greater<int> > q;
    int cmp(int x,int y)
    {
        return x>y;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    vector<int> v[100005];
    int main()
    {
        n=read(),m=read();
        jishu=0;
        for (int i=1;i<=m;i++)
        {
            u=read(),to=read();
            v[u].push_back(to);in[to]++;
        }
        for (int i=1;i<=n;i++) if (in[i]==0) q.push(i);
        while(!q.empty())
        {
            int now=q.top();q.pop();
            ans[++jishu]=now;
            for (int i=0;i<v[now].size();i++)
            {
                int to=v[now][i];
                in[to]--;
                if (in[to]==0&&vis[to]==0) q.push(to),vis[to]=1;
            }
        }
        if (jishu==n) for (int i=1;i<=jishu;i++) printf("%d ",ans[i]);
        else printf("OMG.");
        return 0;
    } 

    T2 神经网络

    题目链接

    ----------------------------------

    拓扑排序裸题,只不过要判定图是否有环,只要在遍历的时候看看是否有最后不为0的in[]即可。

    #include<bits/stdc++.h>
    using namespace std;
    int n,p,u,v,d,head[500005],cnt,c[500005],U,st[500005],top,indgr[500005];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if (ch=='-') f=-1;
            ch=getchar();
        }while('0'<=ch&&ch<='9'){
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    struct node
    {
        int from,to,dis,next;
    }edge[500005];
    void add(int from,int to,int dis)
    {
        edge[++cnt].next=head[from];
        edge[cnt].from=from;
        edge[cnt].to=to;
        edge[cnt].dis=dis;
        head[from]=cnt;
    }
    void topu()
    {
        while(top!=0)
        {
            int now=st[top--];
            if (c[now]<=0){
                for (int i=head[now];i;i=edge[i].next)
                {
                    int to=edge[i].to;
                    indgr[to]--;
                    if (indgr[to]==0) st[++top]=to;
                }
                continue;
            }
            for (int i=head[now];i;i=edge[i].next)
            {
                int to=edge[i].to;
                c[to]+=c[now]*edge[i].dis;
                indgr[to]--;
                if (indgr[to]==0) st[++top]=to;
            }
        }
    }
    int main()
    {
        n=read(),p=read();
        for (int i=1;i<=n;i++)
        {
            c[i]=read(),U=read();
            if (c[i]!=0) st[++top]=i;
            else c[i]-=U;
        }
        for (int i=1;i<=p;i++)
        {
            u=read(),v=read(),d=read();
            add(u,v,d);
            indgr[v]++;
        }
        topu();
        bool flag=0;
        for (int i=1;i<=n;i++)
        {
            if (!head[i]&&c[i]>0){
                cout<<i<<" "<<c[i]<<endl;
                flag=1;
            }
        }
        if (flag==0) cout<<"NULL"<<endl;
        return 0;
     } 

    T3 Fox And Names

    题目链接

    --------------------------------------------

    披着字符串外衣的拓扑排序。注意转换大小写。其实就是神经网络的加强版。

    #include<bits/stdc++.h>
    using namespace std;
    vector<int> v[30];
    int pos[27],n,in[27],sum;
    string a,b;
    int main()
    {
        scanf("%d",&n);
        if (n==1){
            for (char i='a';i<='z';i++) cout<<i;
            return 0;
        }
        cin>>b;
        for (int j=1;j<n;j++)
        {
            a=b; 
            cin>>b;
            for (int i=0;i<a.length();i++)
            {
                if (i>=b.length()){
                    cout<<"Impossible";
                    return 0;
                }
                if (a[i]!=b[i]){
                    v[a[i]-'a'].push_back(b[i]-'a');
                    in[b[i]-'a']++;
                    break;
                }
            }
        }
        queue<int> q;
        for (int i=0;i<26;i++) if (in[i]==0) q.push(i);
        while(!q.empty())
        {
            int now=q.front();q.pop();
            sum++;pos[sum]=now;
            for (int i=0;i<v[now].size();i++)
            {
                in[v[now][i]]--;
                if (in[v[now][i]]==0) q.push(v[now][i]);    
            }    
        }
        if (sum!=26){
            cout<<"Impossible";
            return 0;
        }
        for (int i=1;i<=26;i++) cout<<(char)(pos[i]+'a');
        return 0;
    }

    T4 不相交路径

    这种题属于拓扑排序里比较难的题了,综合性较强,如果没有做题经验会很头疼。

    题目描述+题解

    ------------------------------------

    后记:拓扑排序和DP结合起来也是一类大问题,比如T4。实际上很多DP题目都可以转化成拓扑排序来做,利用题目给的“优先条件”。至于能否转化,要看各位OIer们的功底了。如果有时间,我会专门写一篇关于DP的随笔,包括这类图上DP的题(也许得要到暑假了,现在做题还是太少。

  • 相关阅读:
    多表联合查询,利用 concat 模糊搜索
    order by 中利用 case when 排序
    Quartz.NET 3.0.7 + MySql 动态调度作业+动态切换版本+多作业引用同一程序集不同版本+持久化+集群(一)
    ASP.NET Core 2.2 基础知识(十八) 托管和部署 概述
    ASP.NET Core 2.2 基础知识(十七) SignalR 一个极其简陋的聊天室
    ASP.NET Core 2.2 基础知识(十六) SignalR 概述
    ASP.NET Core 2.2 基础知识(十五) Swagger
    ASP.NET Core 2.2 基础知识(十四) WebAPI Action返回类型(未完待续)
    linux磁盘管理 磁盘查看操作
    linux磁盘管理 文件挂载
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12490003.html
Copyright © 2011-2022 走看看