zoukankan      html  css  js  c++  java
  • 拓扑排序

    给定一个有向图G,对于任意一条有向边<Vi,Vj>,称Vi是Vj的直接前驱,Vj是Vi的直接后继,这种前驱与后继的关系具有传递性。

    如果一个图的任何一个节点都具有反自反性,也就是说任何一个节点都不是自己的前驱或后继,那么这个有向图是拓扑有序的。

    拓扑序列:

    通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。离散数学中关于偏序和全序的定义:
      若集合X上的关系是R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
      设R是集合X上的偏序(Partial Order),如果对每个x,y属于X必有xRy 或 yRx,则称R是集合X上的全序关系。
      注意:
      ①若将图中顶点按拓扑次序排成一行,则图中所有的有向边均是从左指向右的。
      ②若图中存在有向环,则不可能使顶点满足拓扑次序。

      ③一个DAG的拓扑序列通常表示某种方案切实可行。

    拓扑排序的一个应用是可以有向图中是否存在有向环。如果一个有向图存在环,那么必然存在结点不具有反自反性,因而相应的拓扑有序序列是不存在的。。

    拓扑排序方法如下:

      (1)从有向图中选择一个没有前驱(即入度为0)的顶点并且输出它.
      (2)从网中删去该顶点,并且删去从该顶点发出的全部有向边.
      (3)重复上述两步,直到剩余的网中不再存在没有前趋的顶点为止.

     hdu 1285 确定比赛名次 链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285

     解法:拓扑排序,找到一个人,没人能赢他,或者能赢他的人都已经输出,即他的入度为0,则输出此人。注意重边。。。

    代码:

    View Code 
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 int n,m,sum;
     6 int map[501][501],degree[501],a[501],b[501];
     7 void topo(int x)
     8 {
     9     int i;
    10     a[x]=1;
    11     b[++sum]=x;
    12     for(i=1;i<=n;i++)
    13         if(!a[i]&&map[x][i])
    14             degree[i]--;
    15 }
    16 int main()
    17 {
    18     int i,x,y;
    19     while(~scanf("%d%d",&n,&m))
    20     {
    21         memset(map,0,sizeof(map));
    22         memset(degree,0,sizeof(degree));
    23         memset(a,0,sizeof(a));
    24         for(i=0;i<m;i++)
    25         {
    26             scanf("%d%d",&x,&y);
    27             if(map[x][y]==0)
    28             {
    29                 map[x][y]=1;
    30                 degree[y]++;
    31             }
    32         }
    33         sum=0;
    34         while(sum<n)
    35         {
    36             for(i=1;i<=n;i++)
    37             {
    38                 if(degree[i]==0&&a[i]==0)
    39                 {
    40                     topo(i);
    41                     break;
    42                 }
    43             }
    44         }
    45         for(i=1;i<sum;i++)
    46             printf("%d ",b[i]);
    47         printf("%d\n",b[i]);
    48     }
    49     return 0;
    50


    hdu 2094 产生冠军 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2094 

    解法:这个跟上个题基本上一样,确定能不能产生冠军,能产生冠军即入度为0的点只有一个。也可以先用并查集来判断能不能形成连通图。

    代码:

    View Code 
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 using namespace std;
     6 int nu,m,sum;
     7 int map[1001][1001];
     8 int degree[1001];
     9 char s[1001][51];
    10 int a[1001];
    11 int find(char *ss)
    12 {
    13     int i;
    14     for(i=0;i<nu;i++)
    15     {
    16         if(strcmp(ss,s[i])==0)
    17             return i;
    18     }
    19     strcpy(s[i],ss);
    20     return nu++;
    21 }
    22 int topo()
    23 {
    24     int i,l=0;
    25     for(i=0;i<nu;i++)
    26         if(!degree[i])
    27             l++;
    28     return l;
    29 }
    30 int main()
    31 {
    32     char s1[101],s2[101];
    33     int i,x,y;
    34     while(~scanf("%d",&m))
    35     {
    36         if(m==0)
    37             break;
    38         nu=0;
    39         memset(map,0,sizeof(map));
    40         memset(degree,0,sizeof(degree));
    41         memset(a,0,sizeof(a));
    42         for(i=0;i<m;i++)
    43         {
    44             scanf("%s %s",s1,s2);
    45             x=find(s1);
    46             y=find(s2);
    47             if(map[x][y]==0)
    48             {
    49                 map[x][y]=1;
    50                 degree[y]++;
    51             }
    52         }
    53         if(topo()==1)
    54         puts("Yes");
    55         else
    56         puts("No");
    57     }
    58     return 0;
    59

    POJ 1094 Sorting It All Out  链接: http://poj.org/problem?id=1094

    代码:

    View Code 
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 int n,m,j,i,q,flag1;
     6 int map[100][100],degree[100],t[100],b[100];;
     7 int topo()
     8 {
     9     int i,j,f=1,p,temp,k=0;
    10     for(i=0;i<n;i++)
    11         t[i]=degree[i];
    12     for(i=0;i<n;i++)
    13     {
    14         p=0;
    15         for(j=0;j<n;j++)
    16             if(t[j]==0)
    17             {
    18                 p++;
    19                 temp=j;
    20             }
    21         if(p==0)
    22             return 0;
    23         if(p>1)
    24             f=-1;
    25         b[k++]=temp;
    26         t[temp]=-1;
    27         for(j=0;j<n;j++)
    28             if(map[temp][j]!=0)
    29                 t[j]--;
    30     }
    31     return f;
    32 }
    33 int main()
    34 {
    35     while(~scanf("%d %d",&n,&m))
    36     {
    37         flag1=0;
    38         char c1,c2;
    39         if(n==0&&m==0)
    40             break;
    41         memset(map,0,sizeof(map));
    42         memset(degree,0,sizeof(degree));
    43         for(i=0;i<m;i++)
    44         {
    45             scanf("%*c%c<%c",&c1,&c2);
    46             map[c1-'A'][c2-'A']=1;
    47             degree[c2-'A']++;
    48             if(flag1==0)
    49                 q=topo();
    50             if(q==1&&flag1==0)
    51             {
    52                 printf("Sorted sequence determined after %d relations: ",i+1);
    53                 for(j=0;j<n;j++)
    54                     printf("%c",b[j]+'A');
    55                 printf(".\n");
    56                 flag1=1;
    57             }
    58             if(q==0&&flag1==0)
    59             {
    60                 printf("Inconsistency found after %d relations.\n",i+1);
    61                 flag1=1;
    62             }
    63         }
    64         if(flag1==0)
    65             printf("Sorted sequence cannot be determined.\n");
    66     }
    67     return 0;
    68


    POJ 2367 Genealogical tree  链接: http://poj.org/problem?id=2367

    代码:

    View Code 
     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 using namespace std;
     5 const int N=102;
     6 int degree[N],map[N][N],a[N],b[N];
     7 int n,s;
     8 void topo(int x)
     9 {
    10     int i;
    11     a[x]=1;
    12     b[++s]=x;
    13     for(i=1;i<=n;i++)
    14     {
    15         if(!a[i]&&map[x][i])
    16         {
    17             degree[i]--;
    18         }
    19     }
    20 }
    21 int main()
    22 {
    23     int x,i;
    24     scanf("%d",&n);    
    25     memset(a,0,sizeof(0));
    26     memset(degree,0,sizeof(degree));
    27     memset(map,0,sizeof(map));
    28     for(i=1;i<=n;i++)
    29     {
    30         while(1)
    31         {
    32             scanf("%d",&x);
    33             if(x==0)
    34                 break;
    35             map[i][x]=1;
    36             degree[x]++;
    37         }
    38     }
    39     s=0;
    40     while(s<n)
    41     {
    42         for(i=1;i<=n;i++)
    43         {
    44             if(degree[i]==0&&a[i]!=1)
    45             {
    46                 topo(i);
    47             }
    48         }
    49     }
    50     for(i=1;i<n;i++)
    51         printf("%d ",b[i]);
    52     printf("%d\n",b[i]);
    53     return 0;
    54

    poj 3687 Labeling Balls 链接:http://poj.org/problem?id=3687

    题意:n个重量分别为1-n的小球,给定一些小球间的重量关系。 在符合重量关系的前提下,先输出编号小的球。

    分析:拓扑排序,倒着来,注意一下重边。。。

    代码:

    View Code 
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 const int N=210;
     6 int map[N][N],degree[N],a[N],b[N];
     7 int n, m;
     8 void topo()
     9 {
    10     int i,j;
    11     memset(a,0,sizeof(a));
    12     for(i=n;i>0;i--)
    13     {
    14         int q=-1;
    15         for(j=n-1;j>=0;j--)
    16             if(!a[j]&&degree[j]==0)
    17             {
    18                 q=j;
    19                 break;
    20             }
    21         if(q==-1)
    22         {
    23             puts("-1");
    24             return;
    25         }
    26         a[q]=1;
    27         b[q]=i;
    28         for(j=0;j<n;j++)
    29             if(map[q][j])
    30                 degree[j]--;
    31     }
    32     for(i=0;i<n-1;i++)
    33         printf("%d ",b[i]);
    34     printf("%d\n",b[i]);
    35 }
    36 int main()
    37 {
    38     int t;
    39     scanf("%d",&t);
    40     while(t--)
    41     {
    42         int i;
    43         scanf("%d%d",&n,&m);
    44         memset(map,0,sizeof(map));
    45         memset(degree,0,sizeof(degree));
    46         for(i=0;i<m;i++)
    47         {
    48             int a,b;
    49             scanf("%d%d",&a,&b);
    50             a--;
    51             b--;
    52             if(!map[b][a])
    53                 degree[a]++;
    54             map[b][a]=true;
    55         }
    56         topo();
    57     }
    58     return 0;
    59
  • 相关阅读:
    DRF小结
    js中BOM与DOM的概念与区别
    css单位分析、颜色设置与调色板
    css中伪类与伪元素的区别
    flexbox与grid layout的区别
    grid的简单使用
    position属性的总结
    html,css
    homework
    aboutme and my goal
  • 原文地址:https://www.cnblogs.com/pony1993/p/2606678.html
Copyright © 2011-2022 走看看