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的题(也许得要到暑假了,现在做题还是太少。

  • 相关阅读:
    Javascript内容整理——BOM
    前端实现excel报表,vue+luckysheet
    代码转图片 的一个好用网站
    推荐一个非常好用前端在线编辑器!!! 一点都不卡
    前端常用的一些网站
    vue中使用moment,如何按需打包?
    better-scroll
    时间线
    碎纸屑动画
    动画
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12490003.html
Copyright © 2011-2022 走看看