【递归完全搜索】USACO Bronze 2019 December - 奶牛排列Livestock Lineup
题目描述
每天,农夫约翰都会给他的 888 头奶牛挤奶,它们的名字分别是 Bessie、Buttercup、Belinda、Beatrice、Bella、Blue、Betsy 和 Sue。
不幸的是,这些奶牛非常挑剔,要求农夫约翰必须按照满足 N 条约束条件 的顺序来给它们挤奶(1≤N≤71 ≤ N ≤ 71≤N≤7)。
每条约束的格式为:“X 必须和 Y 相邻挤奶”,意思是奶牛 X 必须出现在挤奶顺序中 紧挨着奶牛 Y 的前面或后面。
请帮助农夫约翰确定一个满足所有约束条件的奶牛排列顺序。保证至少存在一种满足条件的顺序。如果有多个顺序满足条件,请输出字典序最小的顺序。即:
- 第一个位置应该选择所有可能的奶牛中名字字典序最小的;
- 如果第一个位置固定后有多个顺序,第二个位置选择字典序最小的,以此类推。
输入格式
第一行是整数 NNN。
接下来的 NNN 行中,每行都是一个约束,格式如下:X must be milked beside Y
其中 XXX 和 YYY 是奶牛的名字(名字只会是上述 888 个中的一个)。
输出格式
输出满足所有约束条件的奶牛排列顺序,共 888 行,每行输出一头奶牛的名字。
样例输入
3
Buttercup must be milked beside Bella
Blue must be milked beside Bella
Sue must be milked beside Beatrice
样例输出
Beatrice
Sue
Belinda
Bessie
Betsy
Blue
Bella
Buttercup
提交链接
Livestock Lineup
思路分析
关键点
只有 888 头奶牛,所有排列数量是 :8!=40320
,完全可以暴力枚举。
next_permutation
可以生成按字典序排列的全排列,第一个合法解就是字典序最小解。
解决步骤
-
读入 NNN 条约束,把每条约束中的两头奶牛记录下来。
-
将 888 头奶牛的名字按字典序排序。
-
枚举所有排列,每次检查所有约束是否满足。
-
找到第一个合法排列后输出并结束。
如何实现这些步骤?
-
读取输入
使用
getline
读入整行约束,然后提取开头和结尾的奶牛名字。 -
存储约束
把每条约束保存为
pair<string,string>
,存入数组。 -
排列生成
将所有奶牛名字放到
vector
,排序后用next_permutation
生成所有字典序排列。 -
合法性检查
对每个排列,遍历所有约束,找出两头奶牛的位置索引,若不相邻则判为不合法。
-
输出结果
第一次遇到合法排列后输出所有奶牛名字,每行一个,然后结束程序。
参考代码
#include <bits/stdc++.h>
using namespace std;int n;
pair<string, string> p[10];
string change(string art)
{string c;for (auto it : art){if (it == ' ')break;c += it;}return c;
}
int main()
{// freopen("lineup.in" , "r" , stdin);// freopen("lineup.out" , "w" , stdout);cin >> n; // n条限制条件getchar();for (int i = 0; i < n; i++){string art;getline(cin, art); // 限制条件// 得到2个奶牛的名字 c1 c2string c1, c2;c1 = change(art);reverse(art.begin(), art.end());c2 = change(art);reverse(c2.begin(), c2.end());p[i] = {c1, c2};}vector<string> cow{"Bessie", "Buttercup", "Belinda", "Beatrice", "Bella", "Blue", "Betsy", "Sue"};sort(cow.begin(), cow.end());do{bool check = true;for (int i = 0; i < n; i++){int l = 0, r = 0;for (int j = 0; j < 8; j++){if (cow[j] == p[i].first)l = j;if (cow[j] == p[i].second)r = j;}if (abs(l - r) != 1)check = false;}if (check){for (auto it : cow)cout << it << endl;break;}} while (next_permutation(cow.begin(), cow.end()));return 0;
}
官方代码
#include <bits/stdc++.h>
using namespace std;int N;
int main() {freopen("lineup.in", "r", stdin);freopen("lineup.out", "w", stdout);cin >> N;vector<pair<string, string>> restrictions;for (int i = 0; i < N; i++) {string a, t, b;cin >> a;cin >> t >> t >> t >> t;cin >> b;restrictions.push_back({a, b});}vector<string> cows = {"Bessie", "Buttercup", "Belinda", "Beatrice","Bella", "Blue", "Betsy", "Sue"};sort(cows.begin(), cows.end());int count = 0;while (next_permutation(cows.begin(), cows.end())) {bool passed = true;for (auto p : restrictions) {string cow1 = p.first;string cow2 = p.second;auto a = find(cows.begin(), cows.end(), cow1);auto b = find(cows.begin(), cows.end(), cow2);if (abs(a - b) != 1) { passed = false; }}if (passed) { break; }}for (auto cow : cows) { cout << cow << endl; }
}