拓扑排序

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

心得: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 }
拓扑排序的思想,更简洁
活在现实,做在梦里。
原文地址:https://www.cnblogs.com/do-it-best/p/5414257.html