• 拓扑排序


    拓扑排序是将一个DAG图的所有顶点排成一个线性序列,使得图中任意一对顶点(u,v)
    若存在边,则u在线性排列中出现在v之前的排列方式
    (1)算法描述:

    (a)从网中选择一个入度为零的顶点输出;

    (b)删除该顶点及其于该点有关的所有边;

    (c)是否还有入度为零的顶点?若有,执行(a),否则结束。

    用邻接矩阵时间复杂度为O(N*N),邻接表的时间复杂度为O(E)

     http://acm.hdu.edu.cn/showproblem.php?pid=1285

    即输出字典序最小的拓扑排序

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stack>
     4 #include <algorithm>
     5 using namespace std;
     6 const int N = 555;
     7 int g[N][N];
     8 int ans[N],in[N];
     9 void topSort(int n, int m)
    10 {
    11     int i,j,k;
    12     for(i=1; i<=n; ++i)
    13         for(j=1; j<=n; ++j)
    14             if(g[i][j])
    15                 in[j]++;//计算每个点的入度
    16     for(i=1; i<=n; ++i)
    17     {
    18         for(j=1; in[j]&&j<=n; ++j)//找到入度为0的点
    19                 NULL;
    20         in[j] = -1;
    21         ans[i]=j;//记录
    22         for(k=1; k<=n; ++k)
    23             if(g[j][k])//删边
    24                 in[k]--;
    25     }    
    26 }
    27 int main()
    28 {
    29     int n,m,i,u,v;
    30     while(scanf("%d%d",&n,&m)!=EOF)
    31     {
    32         memset(g,0,sizeof(g));
    33         memset(in,0,sizeof(in));
    34         for(i=0; i<m; ++i)
    35         {
    36             scanf("%d%d",&u,&v);
    37             g[u][v] = 1;
    38         }
    39         topSort(n,m);
    40         for(i=1; i<=n; ++i)
    41         {
    42             if(i==1)
    43                 printf("%d",ans[i]);
    44             else
    45                 printf(" %d",ans[i]);
    46         }
    47         puts("");
    48     }
    49     return 0;
    50 }
    View Code

     http://acm.hdu.edu.cn/showproblem.php?pid=2647

    给定n个人,m条边

    边u->v表示  u的工资要比v高, 每个人的基础工资为888,问总共的工资最少是多少。

    可以看做是这么一种情况,把整个图分为若干层,层内的工资相等,层与层之间的工资相差1.

    u->v表示u的工资比v高,那么要先确定v才能确定u,那么可以反向建图。

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <vector>
     4 #include <stack>
     5 using namespace std;
     6 const int N = 10000 + 10;
     7 vector<int> g[N];
     8 stack<int> st;
     9 int in[N],add[N],cnt;
    10 inline int max(const int &a, const int &b)
    11 {
    12     return a < b ? b : a;
    13 }
    14 void topSort(int n, int m)
    15 {    
    16     int u,i;
    17     for(i=1; i<=n; ++i)
    18         if(in[i]==0)
    19             st.push(i);
    20     while(!st.empty())
    21     {
    22         u = st.top();//u出栈,表示u的工资已经确定,那么可以推出u指向的顶点的工资
    23         cnt++;
    24         st.pop();
    25         for(i=0; i<g[u].size(); ++i)
    26         {
    27             --in[g[u][i]];
    28             if(in[g[u][i]]==0)
    29                 st.push(g[u][i]);
    30             add[g[u][i]] = max(add[u]+1,add[g[u][i]]);//如果当前的值比前驱加上一的值还小就要更新当前点的值 
    31                 
    32         }
    33     }
    34 }
    35 void init(int n)
    36 {
    37     cnt = 0;
    38     for(int i=1; i<=n; ++i)
    39     {
    40         g[i].clear();
    41         add[i] = in[i] = 0;
    42     }
    43 }
    44 int main()
    45 {
    46     int n,m,i,u,v;
    47     while(scanf("%d%d",&n,&m)!=EOF)
    48     {
    49         init(n);
    50         for(i=0; i<m; ++i)
    51         {
    52             scanf("%d%d",&u,&v);
    53             g[v].push_back(u);//反向建图
    54             in[u]++;
    55         }
    56         topSort(n,m);
    57         int ans = 0;
    58         if(cnt==n)
    59         {
    60             for(i=1; i<=n; ++i)
    61                 ans += add[i] + 888;
    62             printf("%d
    ",ans);
    63         }
    64         else
    65             printf("-1
    ");
    66     }
    67 }
    View Code

     http://acm.hdu.edu.cn/showproblem.php?pid=2647

    给定n个人,m条边

    判断图是不是DAG图。 拓扑排序O(E), bellman O(VE)   , 使用邻接表的dfs O(V+E) ,floyd O(N*N*N)

    其余代码见 http://www.cnblogs.com/justPassBy/p/4342599.html

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <vector>
     4 #include <stack>
     5 using namespace std;
     6 const int N = 10000 + 10;
     7 vector<int> g[N];
     8 stack<int> st;
     9 int in[N],add[N],cnt;
    10 inline int max(const int &a, const int &b)
    11 {
    12     return a < b ? b : a;
    13 }
    14 void topSort(int n, int m)
    15 {    
    16     int u,i;
    17     for(i=1; i<=n; ++i)
    18         if(in[i]==0)
    19             st.push(i);
    20     while(!st.empty())
    21     {
    22         u = st.top();
    23         cnt++;
    24         st.pop();
    25         for(i=0; i<g[u].size(); ++i)
    26         {
    27             --in[g[u][i]];
    28             if(in[g[u][i]]==0)
    29                 st.push(g[u][i]);
    30         
    31                 
    32         }
    33     }
    34 }
    35 void init(int n)
    36 {
    37     cnt = 0;
    38     for(int i=1; i<=n; ++i)
    39     {
    40         g[i].clear();
    41         add[i] = in[i] = 0;
    42     }
    43 }
    44 int main()
    45 {
    46     int n,m,i,u,v;
    47     while(scanf("%d%d",&n,&m)!=EOF)
    48     {
    49         if(n==0 && m==0)
    50             break;
    51         init(n);
    52         for(i=0; i<m; ++i)
    53         {
    54             scanf("%d%d",&u,&v);
    55             u++;
    56             v++;
    57             g[u].push_back(v);
    58             in[v]++;
    59         }
    60         topSort(n,m);
    61         if(cnt==n)//能生成n个顶点的序列,说明是DAG图
    62         {
    63             puts("YES");
    64         }
    65         else
    66             puts("NO");
    67     }
    68 }
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=1811

    根据所给的信息判定能否确定唯一排名。

    题目的难点在于=号的处理。  我们可以利用并查集将相等的结点并在一个集合里。然后再使用拓扑排序就可以了。

    1、如果每次入栈的结点大于1个,那么拓扑排序不唯一。 这很好理解

    2、如果出栈的顶点个数小于总顶点个数,那么存在回路。

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <vector>
      4 #include <stack>
      5 using namespace std;
      6 const int N = 10000 + 10;
      7 int u[N],v[N];
      8 int in[N],father[N];
      9 char str[N][2];
     10 vector<int> g[N];
     11 stack<int> st;
     12 int ans,cnt;
     13 void init(int n)
     14 {
     15     ans = cnt = 0;
     16     for(int i=0; i<=n; ++i)
     17     {
     18         in[i] = 0;
     19         father[i] = i;
     20         g[i].clear();
     21     }
     22 }
     23 int topSort(int n, int m)
     24 {
     25     int i,tmp = 0,flag = 0,k = 0;
     26     for(i=0; i<n; ++i)
     27         if(father[i]==i)
     28         {
     29             cnt++;
     30             if(in[i]==0)
     31             {
     32                 st.push(i);
     33                 tmp++;
     34             }
     35             if(tmp>1)//如果一次入栈的结点大于1个,那么就说明拓扑排序不唯一
     36                 flag = 2;
     37         }
     38     while(!st.empty())
     39     {
     40         int u = st.top();
     41         st.pop();
     42         k++;
     43         tmp = 0;
     44         for(i=0; i<g[u].size(); ++i)
     45         {
     46             int v = g[u][i];
     47             in[v]--;
     48             if(in[v]==0)
     49             {
     50                 tmp++;
     51                 st.push(v);
     52             }
     53         }
     54         if(tmp>1) flag = 2;
     55     }
     56     if(k < cnt) flag = 1;//存在回路
     57     return flag;
     58 }
     59 int find(int x)
     60 {
     61     if(x == father[x])
     62         return x;
     63     return father[x] = find(father[x]);
     64 }
     65 int main()
     66 {
     67     int n,m,i,ru,rv;
     68     while(scanf("%d%d",&n,&m)!=EOF)
     69     {
     70         init(n);
     71         for(i=0; i<m; ++i)
     72         {    
     73             scanf("%d%s%d",&u[i],str[i],&v[i]);
     74             if(str[i][0]=='=')//将相等的结点并在一个集合里
     75             {
     76                 ru = find(u[i]);
     77                 rv = find(v[i]);
     78                 if(ru!=rv)
     79                     father[ru] = rv;
     80             }
     81         }
     82         for(i=0; i<n; ++i) find(i);//这样就能用father[i]得到i的父亲
     83         for(i=0; i<m; ++i)
     84         {
     85             if(father[u[i]] == father[v[i]] && str[i][0]!='=')
     86             {
     87                 ans = 1;
     88                 break;
     89             }
     90             else if(str[i][0]=='>')
     91             {
     92                 g[father[u[i]]].push_back(father[v[i]]);
     93                 in[father[v[i]]]++;
     94             }    
     95             else if(str[i][0]=='<')
     96             {
     97                 g[father[v[i]]].push_back(father[u[i]]);
     98                 in[father[u[i]]]++;
     99             }
    100         }
    101         if(!ans) ans = topSort(n,m);
    102         if(!ans) puts("OK");
    103         else if(ans==1) puts("CONFLICT");
    104         else puts("UNCERTAIN");
    105     }
    106     return 0;
    107 }
    View Code

    http://poj.org/problem?id=1094

    给定n个点,m条边,

    要我们逐步判断随着边的增加,能否确定唯一拓扑排序,或者是否有环。  否则就是不能确定

    先判断有没有环,如果有环,输出有环

    如果没有环,那么拓扑判断是否能确定唯一排序

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <vector>
      4 using namespace std;
      5 const int N = 30;
      6 int g[N][N],start,n,m,in[N],ans[N];
      7 bool vis[N],vis2[N],hasCircle,confirmSequeue;
      8 void dfs(int u)
      9 {
     10     for(int i=0; i<n; ++i)
     11     {
     12         if(g[u][i]==1)
     13         {
     14             if(start==i)
     15             {
     16                 hasCircle = true;
     17                 return;
     18             }
     19             if(!vis2[i])
     20             {
     21                 vis2[i] = true;
     22                 dfs(i);
     23             }
     24             
     25         }
     26     }
     27 }
     28 void topSort()
     29 {
     30     int i,j,k;
     31     for(i=0; i<n; ++i)
     32         for(j=0; j<n; ++j)
     33             if(g[i][j])
     34                 in[j]++;
     35     int cnt     = 0;
     36     for(j=0; j<n; ++j)
     37         if(in[j]==0)
     38             cnt++;
     39     if(cnt>1)//不能确定唯一拓扑排序
     40     {
     41         confirmSequeue = false;
     42         return;
     43     }
     44     for(i=0; i<n; ++i)
     45     {
     46         for(j=0;in[j]&&j<n;++j)
     47             NULL;
     48         in[j] = -1;
     49         ans[i] = j;
     50         cnt = 0;
     51         for(k=0; k<n; ++k)
     52         {
     53             if(g[j][k])
     54             {
     55                 in[k]--;
     56                 if(in[k]==0)
     57                 cnt++;
     58             }    
     59             if(cnt>1)
     60             {
     61                 confirmSequeue = false;
     62                 return;
     63             }    
     64         }
     65     }
     66 }
     67 int main()
     68 {
     69     int i,cnt,u,v,j;
     70     char str[5];
     71     while(true)
     72     {
     73         scanf("%d%d",&n,&m);
     74         if(n==0 && m==0) break;
     75         memset(vis,0,sizeof(vis));
     76         memset(g,0,sizeof(g));
     77         hasCircle = false;
     78         confirmSequeue = true;
     79         cnt = 0;
     80         for(i=0; i<m; ++i)
     81         {
     82             scanf("%s",str);
     83             u = str[0] - 'A';
     84             v = str[2] - 'A';
     85             g[u][v] = 1;
     86             if(!vis[u]) {vis[u] = true; cnt++;}
     87             if(!vis[v]) {vis[v] = true; cnt++;}
     88             for(j=0; j<n; ++j)//dfs判断是否有环
     89             {
     90                 memset(vis2,0,sizeof(vis2));
     91                 vis2[j] = true;
     92                 start = j;
     93                 dfs(j);
     94                 if(hasCircle) break;
     95             }
     96             if(hasCircle) break;
     97             if(cnt==n)//有n个顶点的时候才进行拓扑排序
     98             {
     99                 confirmSequeue = true;
    100                 memset(in,0,sizeof(in));
    101                 topSort();
    102                 if(confirmSequeue)
    103                     break;
    104             }
    105         }
    106         if(cnt == n && confirmSequeue)
    107         {
    108             printf("Sorted sequence determined after %d relations: ",i+1);
    109             for(j=0; j<n; ++j)
    110                 printf("%c",ans[j]+'A');
    111             puts(".");
    112         }    
    113         else if(hasCircle)
    114             printf("Inconsistency found after %d relations.
    ",i+1);
    115         else
    116             printf("Sorted sequence cannot be determined.
    ");
    117         for(i++;i<m; ++i) 
    118             scanf("%s",str);
    119     }
    120 }
    View Code
  • 相关阅读:
    Divide by Zero 2017 and Codeforces Round #399 (Div. 1 + Div. 2, combined) C
    Divide by Zero 2017 and Codeforces Round #399 (Div. 1 + Div. 2, combined) B. Code For 1
    引入CSS文件的方式,以及link与@import的区别
    JavaScript
    css
    html
    CentOS 7编译安装Python3.7.X
    python3配置爬虫开发环境
    Threading模块
    队列Queue的get方法
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4342150.html
Copyright © 2020-2023  润新知