Time limit: 3.000 seconds
限时:3.000秒
Background
背景
Order is an important concept in mathematics and in computer science. For example, Zorn's Lemma states: "a partially ordered set in which every chain has an upper bound contains a maximal element." Order is also important in reasoning about the fix-point semantics of programs.
有序在数学和计算机学中是一个非常重要的概念。例如佐恩引理所述:“在任何一个偏序集中,如何任何链(译注:即有序子集)都有上界,那么这个偏序集必然存在一个最大元素。”有序概念在程序的定点语义推理中也是非常重要的。
This problem involves neither Zorn's Lemma nor fix-point semantics, but does involve order.
但是本问题并不涉及佐恩引理和定点语义这些复杂理论,仅仅是关于有序。
The Problem
问题
Given a list of variable constraints of the form x < y, you are to write a program that prints all orderings of the variables that are consistent with the constraints.
给定一组变量和一个约束x < y,你要写一个程序打印出所有由这些变量组成并能满足该约束的有序集。
For example, given the constraints x < y and x < z there are two orderings of the variables x, y, and z that are consistent with these constraints: x y z and x z y.
举例来说,给定约束x < y和x < z,那么x、y和z三个变量就可以组成两个满足该约束的有序集:x y z和 x z y。
The Input
输入
The input consists of a sequence of constraint specifications. A specification consists of two lines: a list of variables on one line followed by a list of constraints on the next line. A constraint is given by a pair of variables, where x y indicates that x < y.
输入包括一系列的约束定义。每个定义包括两行:第一行是一组变量,第二行是一组约束。每个约束包含两个变量,如x y表示x < y。
All variables are single character, lower-case letters. There will be at least two variables, and no more than 20 variables in a specification. There will be at least one constraint, and no more than 50 constraints in a specification. There will be at least one, and no more than 300 orderings consistent with the contraints in a specification.
所有变量都是单个小写字母。定义中最少有两个变量,最多不超过20个变量;最少有一个约束,最多不超过50个约束。存在的有序集最少一个,最多不超过300个。
Input is terminated by end-of-file.
输入由EOF表示结束。
The Output
输出
For each constraint specification, all orderings consistent with the constraints should be printed.
对应于每个约束的定义,应打印输出全部满足该约束的有序集。
Orderings are printed in lexicographical (alphabetical) order, one per line.
有序集以字母表顺序打印,每行一个。
Output for different constraint specifications is separated by a blank line.
对于不同约束条件的有序集之间以空行隔开。
Sample Input
示例输入
a b f g
a b b f
v w x y z
v y x v z v w v
Sample Output
示例输出
abfg
abgf
agbf
gabf
wxzvy
wzxvy
xwzvy
xzwvy
zwxvy
zxwvy
Analysis
分析
这是一道比较典型的全排列生成问题,只是生成的每一个排列都要满足给定的条件,且必须按顺序生成。我们当然可以简单的利用STL里的next_permutation函数来解决这个问题,事实上这是非常容易的。关于next_permutation和prev_permutation这两个神奇函数的内部算法,请参见我的另一篇文章:全排列生成算法。
回到本问题的解答,既然已经可以按照题目要求的字母表顺序生成全排列,那么现在的问题就是如何使生成的排列符合给定的约束。最简单的办法就是检查已生成序列中是否存在违背约束的字母对,当然是要用双重循环遍例字符串中的所有字母对。由于最多只有26个字母,因此为加快速度,可以建立一个26×26的二维数组来表示两个字母间是否给定了大于的约束关系。检查生成的排列时,如果发现了某一对字母逆向的符合了这个关系表中对应的结点,则认为是非法的排列。
Solution
解答
#include <algorithm> #include <iostream> #include <string> using namespace std; //主函数 int main(void) { bool bFirst = true; char szOrder[24]; //循环读取并处理每一个组原字符串和约束 for (string str; getline(cin, str); bFirst = false) { //为加快速度,便于处理,将原字符串转存到数组中 strcpy(szOrder, str.c_str()); //去掉原字符串中间的空格 int nLen = remove(szOrder, &szOrder[str.size()], ' ') - szOrder; szOrder[nLen] = '\0'; //获取约束串 getline(cin, str); //去掉约束串中间的空格 str.erase(remove(str.begin(), str.end(), ' '), str.end()); //生成约束关系表,如果存在约束i > j,则aCompMat[i][j]为true bool aCompMat[26][26] = {0}; for (string::iterator i = str.begin(); i != str.end(); i += 2) { aCompMat[*i - 'a'][*(i + 1) - 'a'] = true; } //将原字符串从大到小排序,准备生成全排列 sort(&szOrder[0], &szOrder[nLen]); //如果不是第一次,要按要求在第一行输出一个回车 if (!bFirst) { cout << endl; } //bFlag为false表示发现该顺序不满足约束。每次生成下一组全排列 for (bool bFlag = true; bFlag; bFlag = next_permutation( &szOrder[0], &szOrder[nLen])) { //循环判断当前生成的顺序中是否每一对字符都满足约束 for (int i = 0; i < nLen - 1 && bFlag; ++i) { for (int j = i + 1; j < nLen && bFlag; ++j) { //出现逆序,即aCompMat[j][i] = true,即不满足 bFlag &= !aCompMat[szOrder[j] - 'a'][szOrder[i] - 'a']; } } //如果全满足约束,则输出有序集 if (bFlag) { cout << szOrder << endl; } } } return 0; }
作者:王雨濛;新浪微博:@吉祥村码农;来源:《程序控》博客 -- http://www.cnblogs.com/devymex/ 此文章版权归作者所有(有特别声明的除外),转载必须注明作者及来源。您不能用于商业目的也不能修改原文内容。 |