题目描述
顺序是数学和计算机科学中的一个重要概念。例如,Zorn 的引理指出:“一个偏序集合,其中每个链都有一个上限,其中包含一个最大元素。” 顺序在推理程序的定点语义时也很重要。
这个问题既不涉及Zorn的引理也不涉及定点语义,但涉及顺序。
给定 x < y 形式的变量约束列表,您将编写一个程序,打印与约束一致的变量的所有排序。
例如,给定约束 x < y 和 x < z,变量 x、y 和 z 的两个排序与这些约束一致:x y z 和 x z y。
输入
输入由一系列约束规范组成。规范由两行组成:一行是变量列表,下一行是约束列表。约束由一对变量给出,其中 x y 表示 x < y。
所有变量都是单字符、小写字母。规范中至少有两个变量,并且不超过 20 个变量。规范中至少有一个约束,并且不超过 50 个约束。将至少有一个,并且不超过 300 个与规范中的约束一致的排序。
输入由文件结尾终止。
输出
对于每个约束规范,应打印所有与约束一致的排序。 排序按字典(字母)顺序打印,每行一个。
不同约束规范的输出由空行分隔.
输入样例
a b f g
a b b f
v w x y z
v y x v z v w v
输出样例
abfg
abgf
agbf
gabf
wxzvy
wzxvy
xwzvy
xzwvy
zwxvy
zxwvy
思路:这个题的意思是给出序列点以及相对应的大小关系,然后进行拓扑排序输出.但结果要的是所有的拓扑序列.这就要求我们在编写代码时每成功输出一个就得及时进行回溯.
由于输出所有,也就不能使用栈了,因为栈会把所有的次序进行固定.我们考虑使用for循环.结合着DFS+回溯思想便可轻易搞定.
通过观察样例我们可知,字母的输入并不是按照字母序的,可能乱序.所以for循环时得遍历26个字母.
输入输出比较特殊,需要注意下.
参考代码
#include<iostream>
#include<string.h>
#include<string>
using namespace std;
const int maxn = 30;
int map[maxn][maxn],book[maxn],topo[maxn],in[maxn],n;//n个顶点 book:标记是否
void dfs(int t){//t:代表topo中数的个数.
if(t==n){//结束条件
for(int i = 0;i < n; i++){
cout<<char(topo[i]+'a'-1);
}
cout<<endl;
return;
}
for(int i = 1; i <= 26; i++){ //因为输入的字符不一定是按照给的个数从前往后的那些字母还可能是乱序的字符.所以每一个都应该进行遍历.
if(!in[i]&&book[i]){//如果该点存在,且入度为0
topo[t] = i;//将其加入拓扑序列
book[i] = 0;//在图中删除该点 ,下次就不能使用该点了.
for(int j = 1; j <= 26; j++){
if(map[i][j]){
in[j]--;
}
}
dfs(t+1);//进行下一轮
//进行回溯,因为此刻还可能有其他的点满足条件.
book[i] = 1;
for(int j = 1; j <= 26; j++){
if(map[i][j]){
in[j]++;
}
}
}
}
}
int main()
{
string str,str2;
while(getline(cin,str)){
//初始化
memset(map,0,sizeof(map));
memset(book,0,sizeof(book));
memset(topo,0,sizeof(topo));
memset(in,0,sizeof(in));
n = 0;
for(int i = 0; i < str.size(); i++){
if(str[i]!=' '){
n++;
book[str[i]-'a'+1] = 1;
}
}
// cout<<"==============================="<<endl;
// for(int i = 1;i <= 26; i++){
// cout<<book[i]<<"\t";
// }
// cout<<"==============================="<<endl;
getline(cin,str2);
for(int i = 0; i < str2.size(); i=i+2){
char ch1 = str2[i];
i+= 2;
char ch2 = str2[i];
map[ch1-'a'+1][ch2-'a'+1] = 1;
in[ch2-'a'+1]++;
}
dfs(0);
cout<<endl;
}
return 0;
}