• 拓扑排序


    今天看到的一篇博文,超赞

    心得:Topsort不仅用于job/work的排序,字典序的排序,还可以适用于任意具有偏序关系的问题,

    只要可以把问题转换为有向无环图,然后知晓其偏序,之后就是表示边/入度,然后用拓扑排序的思想去计算。

    注意拓扑排序的唯一性是在全序关系的条件下建立起来的

    注意拓扑排序是针对有向五环图。

    欧拉回路和哈密顿路径:

    哈密顿路径:经过所有的顶点正好访问一次的路径。

    Knhn算法的实现:考虑入度为0的点

    DFS算法的实现:考虑出度为0的点

    uva,200

    一开始没看懂,后来知道了,是给你几行索引是按照一种语言的字典序排序的

    例如: xwy zx  z>x   zxy zxw  w>y  zxw ywwx  y>z   最后字母的大小顺序  x<z<y<w

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <string>
     4 #include <vector>
     5 using namespace std;
     6 
     7 vector<char> ans;
     8 vector<char> toPoint[100];
     9 int visit[100] = {0};
    10 int deg[100] = {0}; // deg[i]=1:沒有被其他點連入 deg[i]=2:被其他點連入
    11 void DFS(char n);
    12 
    13 int main()
    14 {
    15   //  freopen("input.txt","rt",stdin);
    16     ios::sync_with_stdio(false);
    17     string a, b;
    18     cin >> a;
    19     while (cin >> b && b != "#") {
    20         int L = (a.size() > b.size()) ? b.size() : a.size();
    21         for (int i = 0; i < L; ++i) {
    22             if (deg[a[i]] == 0) deg[a[i]] = 1;
    23             if (deg[b[i]] == 0) deg[b[i]] = 1;
    24             if (b[i] != a[i]) {
    25                 toPoint[a[i]].push_back(b[i]);
    26                 deg[b[i]] = 2;
    27                 break;
    28             }
    29         }
    30         a = b;
    31     }
    32     for (char i = 'A'; i <= 'Z'; ++i)
    33         if (deg[i] == 1)
    34             DFS(i);
    35 
    36     for (auto iter = ans.rbegin(); iter != ans.rend(); ++iter)
    37         cout << *iter;
    38     cout << endl;
    39 }
    40 void DFS(char n)
    41 {
    42     if (visit[n] == 1) return;
    43     visit[n] = 1;
    44 
    45     for (char nxt : toPoint[n])
    46         if (visit[nxt] != 2)
    47             DFS(nxt);
    48     visit[n] = 2;
    49     ans.push_back(n);
    50 }
    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 
     5 using namespace std;
     6 
     7 char list[10001][100];
     8 int map[27][27];
     9 int used[27];
    10 int stack[27];
    11 int stack_size=0;
    12 
    13 void dfs(int s)
    14 {
    15     used[s]=0;
    16     for(int i=0;i<27;++i)
    17         if(used[i] && map[s][i])
    18             dfs(i);
    19     stack[stack_size++]=s+'A';
    20 }
    21 
    22 int main()
    23 {
    24     int count=0;
    25     while(scanf("%s",list[count]) && list[count][0]!='#')
    26         count++;
    27     memset(used,0,sizeof(used));
    28     memset(map,0,sizeof(map));
    29     used[list[0][0]-'A']=1;
    30     
    31     for(int i=1;i<count;i++)
    32     {
    33         for(int p=0,q=0;list[i-1][p] && list[i][q];++p,++q)
    34         {
    35             
    36             used[list[i-1][p]-'A']=used[list[i][q]-'A']=1;
    37             if(list[i-1][p]!=list[i][q])
    38             {
    39                 map[list[i-1][p]-'A'][list[i][q]-'A']=1;
    40                 used[list[i][q]-'A']=2;
    41                 break;
    42             }
    43         }
    44     }
    45     
    46     for(int i=0;i<27;i++)
    47         if(used[i]==1)
    48             dfs(i);
    49     while(stack_size--)
    50         printf("%c",stack[stack_size]);
    51     printf("
    ");
    52     return 0;
    53         
    54 }
    View Code

    uva,10305

    dfs搞一搞就可以了

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

     uva,124

    参考了大神的代码,第一次接触拓扑排序,我还只停留在一维的思想上,只会打印一组拓扑排序结果,

    用dfs把每种可能的结果都搜一下,然后加上限制条件,如果满足len=n则输出。。。。。真的妙!!!豁然开朗

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 #include <algorithm>
     6 #include <cstdlib>
     7 
     8 using namespace std;
     9 const int maxn=200;
    10 
    11 char ch1[maxn],ch2[maxn],ch3[maxn];
    12 int n,m,a[maxn],edge[maxn][maxn],to[maxn],vis[maxn],zm[maxn];
    13 
    14 bool cmp(char a,char b)
    15 {
    16     return a<b;
    17 }
    18 
    19 void dfs(int len)
    20 {
    21     if(n==len) //当深度为n,也就是把每个点都访问一次
    22     {
    23         for(int i=0;i<n;i++)
    24             printf("%c",ch3[a[i]]); //打印
    25         printf("
    ");
    26         return;
    27     }
    28     
    29     for(int i=0;i<n;i++)
    30     {
    31         if(!vis[i] && !to[i])
    32         {
    33             for(int j=0;j<n;j++)
    34                 if(edge[i][j]==1)  //删边
    35                     to[j]--;
    36             vis[i]=1;
    37             a[len]=i;
    38             dfs(len+1);
    39             
    40             for(int j=0;j<n;j++)
    41                 if(edge[i][j]==1)  //恢复现场,为下一个序列做准备
    42                     to[j]++;
    43             vis[i]=0;
    44         }
    45     }
    46     return;
    47 }
    48 
    49 int main()
    50 {
    51     int pd=0;
    52     while(gets(ch1))
    53     {
    54         int i;
    55         if(!pd)
    56             pd=1;
    57         else
    58             printf("
    ");
    59         
    60         
    61         for(i=0,n=0;ch1[i];i++)
    62         {
    63             if(ch1[i]==' ')
    64                 continue;
    65             ch3[n++]=ch1[i];  //筛选
    66         }
    67         
    68         sort(ch3,ch3+n,cmp); //按字典序
    69         
    70         memset(zm,-1,sizeof(zm));
    71         memset(edge,-1,sizeof(edge));
    72         memset(to,0,sizeof(to));
    73         memset(vis,0,sizeof(vis));
    74         
    75         for(int i=0;i<n;i++)
    76         {
    77             zm[ch3[i]-'a']=i;  //剪枝,大大降低整体复杂度
    78         } 
    79         
    80         gets(ch2);
    81         
    82         for(i=0;ch2[i];i+=4)
    83         {
    84             edge[zm[ch2[i]-'a']][zm[ch2[i+2]-'a']]=1;  //建边
    85             to[zm[ch2[i+2]-'a']]++;  //入度增1
    86         }
    87         dfs(0);
    88     }
    89     return 0;
    90 }
    View Code

    对next_permutation函数求出所以的排列,然后限制条件,最后输出。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 #include <cstdlib>
     6 #include <algorithm>
     7 
     8 using namespace std;
     9 const int maxn=200;
    10 
    11 char ch1[maxn],ch2[maxn],ch3[maxn];
    12 int n,edge[maxn][maxn],to[maxn],vis[maxn],a[maxn],zm[maxn];
    13 
    14 
    15 bool cmp(char a,char b)
    16 {
    17     return a<b;
    18 }
    19 
    20 int Topsort(char ch[])
    21 {
    22     for(int i=n-1;i>0;i--)
    23         for(int j=i-1;j>=0;j--)
    24             if(edge[zm[ch[i]-'a']][zm[ch[j]-'a']]==1)
    25                 return 0;
    26     return 1;
    27 }
    28 
    29 int main()
    30 {
    31     int i,pd=0;
    32     while(gets(ch1))
    33     {
    34         if(!pd)
    35             pd=1;
    36         else
    37             printf("
    ");
    38         gets(ch2);
    39         for(i=0,n=0;ch1[i];i++)
    40         {
    41             if(ch1[i]==' ')
    42                 continue;
    43             ch3[n++]=ch1[i];
    44         }
    45         ch3[n]='';
    46         sort(ch3,ch3+n,cmp);
    47         memset(edge,-1,sizeof(edge));
    48         memset(vis,0,sizeof(vis));
    49         memset(to,0,sizeof(to));
    50         memset(zm,-1,sizeof(zm));
    51         
    52         
    53         for(i=0;i<n;i++)
    54         {
    55             zm[ch3[i]-'a']=i;
    56         }
    57         
    58         for(i=0;ch2[i];i+=4)
    59         {
    60             edge[zm[ch2[i]-'a']][zm[ch2[i+2]-'a']]=1;
    61             to[zm[ch2[i+2]-'a']]++;
    62         }
    63         
    64         if(Topsort(ch3))
    65             printf("%s
    ",ch3);
    66         while(next_permutation(ch3,ch3+n))
    67         {
    68             if(Topsort(ch3))
    69                 printf("%s
    ",ch3);
    70         }
    71     }
    72     return 0;
    73 }
    next_permutation重写

    uva,196

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<string>
      4 #include<algorithm>
      5 #include<queue>
      6 #include<vector>
      7 #include<iostream>
      8 #include<cmath>
      9 using namespace std;
     10 const int maxn=2000005;                        // 开到百万即可
     11 int row,col;                                   // 行,列
     12 int val[maxn];                                 // 数值
     13 int GetId(int x,int y){ return (x-1)*col+y; }  // 得到某个位置的id
     14 string S[maxn];   
     15 vector<int> G[maxn];                           // 用动态数组建立临接表,我比较喜欢用这种方式
     16 int indeg[maxn];                               // 入度
     17 int Get(const string& str)                     // 如果格子中是数值,则调用这个函数
     18 {
     19     int ret=0;
     20     for(int i=0;i<str.size();i++)  ret=ret*10+str[i]-'0';
     21     return ret;
     22 }
     23 void change_to_num(const string& str,int id)
     24 {
     25     int i;
     26     for(i=0;i<str.size();i++)
     27     {
     28         if(str[i]>='0'&&str[i]<='9')  break;           //  找到字母和数字的分界位置
     29     }
     30     int R=0,C=0;
     31     for(int j=0;j<i;j++) C=C*26+str[j]-'A'+1;          // 分别计算行跟列
     32     for(int j=i;j<str.size();j++)  R=R*10+str[j]-'0';
     33     int to=GetId(R,C);
     34     G[to].push_back(id);                               // 建表
     35     indeg[id]++;                                        
     36 }
     37 void link(const string& str,int id)
     38 {
     39     int pre=1;                                            
     40     int i;
     41     for(i=1;i<str.size();i++)
     42     {
     43         if(str[i]=='+')
     44         {
     45             change_to_num(str.substr(pre,i-pre),id);     //单独分离出来如=A1+B1+C1,分离出A1,B1,
     46             pre=i+1;
     47         }
     48     }
     49     change_to_num(str.substr(pre,i-pre),id);             // 最后一个还要处理,如分离出最后的C1
     50 }
     51 void Get_Val(const string& str,int id)
     52 {
     53     if(str[0]!='=')   val[id]=Get(str);                  // 如果是数值
     54     else   link(str,id);                                 // 要建立临接表
     55 }
     56 queue<int> que;
     57 void toposort()
     58 {
     59     while(!que.empty())  que.pop();
     60     for(int i=1;i<=row*col;i++)  if(!indeg[i])  que.push(i);    //入度为0 的加入队列
     61     while(!que.empty())
     62     {
     63         int now=que.front(); que.pop();
     64         for(int i=0;i<G[now].size();i++)
     65         {
     66             int to=G[now][i];
     67             indeg[to]--;
     68             val[to]+=val[now];                              //加上数值
     69             if(!indeg[to])  que.push(to);                   //变为0就加入队列
     70         }
     71     }
     72 }
     73 void ans_print()
     74 {
     75     for(int i=1;i<=row;i++)
     76     {
     77         for(int j=1;j<=col;j++)
     78         {
     79             if(j!=1)  printf(" ");
     80             printf("%d",val[GetId(i,j)]);
     81         }
     82         printf("
    ");
     83     }
     84 }
     85 int main()
     86 {
     87     int T;
     88     scanf("%d",&T);
     89     while(T--)
     90     {
     91         scanf("%d%d",&col,&row);
     92         memset(val,0,sizeof(val));
     93         for(int i=1;i<=row*col;i++)  G[i].clear();
     94         memset(indeg,0,sizeof(indeg));
     95         for(int i=1;i<=row;i++)
     96         {
     97             for(int j=1;j<=col;j++)
     98             {
     99                 int id=GetId(i,j);         // 得到他的id
    100                 cin>>S[id];
    101                 Get_Val(S[id],id);         // 处理
    102             }
    103         }
    104         toposort();                        // 拓扑排序
    105         ans_print();                       // 打印
    106     }
    107     return 0;
    108 }
    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 #include <cmath>
     6 #include <algorithm>
     7 #include <cstdlib>
     8 #define maxn 1010
     9 #define MARK -2147483645
    10 
    11 using namespace std;
    12 
    13 int row,col;
    14 int sheet[maxn][maxn];
    15 string str;
    16 string formula[maxn][maxn];
    17 
    18 
    19 int dfs(int r,int c)
    20 {
    21     if(sheet[r][c]!=MARK) return sheet[r][c];
    22     if(sheet[r][c]==MARK)
    23     {
    24         int m_col,m_row;
    25         
    26         string str=formula[r][c];
    27         sheet[r][c]=0;
    28         char temp[maxn];
    29         
    30         for(int i=1,pos=0;i<=str.size()+1;i++)
    31         {
    32             int k;
    33             if(str[i]=='+' || i==str.size())
    34             {
    35                 m_col=0;m_row=0;
    36                 temp[pos]='';
    37                 for(k=0; k<strlen(temp) && !isdigit(temp[k]);++k)
    38                     m_col=m_col*26+temp[k]-'A'+1;
    39                 for(;k<strlen(temp);++k)
    40                     m_row=m_row*10+temp[k]-'0';
    41                 
    42                 pos=0;
    43                 sheet[r][c]+=dfs(m_row,m_col);
    44             }
    45             else
    46                 temp[pos++]=str[i];
    47                 
    48         }
    49     }
    50     return sheet[r][c];
    51 }
    52 
    53 int main()
    54 {
    55     int t;
    56     scanf("%d",&t);
    57     while(t--)
    58     {
    59         scanf("%d%d",&col,&row);
    60         memset(sheet,0,sizeof(sheet));
    61         
    62         for(int i=1;i<=row;i++)
    63             for(int j=1;j<=col;j++)
    64             {
    65                 cin>>str;
    66                 if(str[0]=='=')
    67                 {
    68                     sheet[i][j]=MARK;
    69                     formula[i][j]=str;
    70                 }
    71                 else
    72                     sheet[i][j]=atoi(str.c_str());
    73             }
    74         
    75         for(int i=1;i<=row;i++)
    76             for(int j=1;j<=col;j++)
    77                 if(sheet[i][j]==MARK)
    78                 {
    79                     dfs(i,j);
    80                 }
    81         for(int i=1;i<=row;i++)
    82         {
    83             for(int j=1;j<=col;j++)
    84             {
    85                 if(j!=1)
    86                     printf(" ");
    87                 printf("%d",sheet[i][j]);
    88             }
    89             printf("
    ");
    90         }
    91     }
    92     return 0;
    93 }
    拓扑排序的思想,更简洁
    活在现实,做在梦里。
  • 相关阅读:
    所谓经济现象
    高旻寺德林老和尚开示
    3Delight NSI: A Streamable Render API
    Play vue.js with constant value in SailsJS
    天魔心法之——识人篇
    对国内IoT的展望
    对国内AR产业的预言
    简评某中国工程师嫌疑窃取苹果自动驾驶技术
    评估人类的金三角模型
    Odoo 进销存报表现已开源
  • 原文地址:https://www.cnblogs.com/do-it-best/p/5414257.html
Copyright © 2020-2023  润新知