题目
题目链接
给出几个互相交错的框,输出交叠的顺序,根据题意,每个由字母组成的框(frame)的每一个边都会至少有一个字母在交叠后的图中,所以扫描一遍输入图就可以得到边界。扫描其中一个框Y,如果边上有其他字母X,则构造一条边 X -> Y,表明框X在框Y之上。
算法
使用回溯法(深度优先搜索),保存每一个可能的排序。即如果当前存在两个入度为0的节点A、B,先保存A或先保存B。
代码
#include<iostream>
#include<vector>
#include<string>
#include <unordered_set>
#include <list>
#include <algorithm>
using namespace std;
struct Frame{
int x1, x2, y1, y2;
char letter;
Frame(){
this->letter = '.';
x1 = y1 = 0x7fffffff;
x2 = y2 = 0;
}
};
void dfs(vector<string>& ans, list<char>& seq, vector<int>& count, unordered_set<char>& letters, const vector<vector<bool>>& graph) {
if (seq.size() == letters.size()) {
ans.emplace_back(seq.begin(), seq.end());
} else {
for (auto& c : letters) {
if (count[c-'A'] == 0 && seq.end() == find(seq.begin(), seq.end(), c)) {
for (auto& l : letters) {
if (graph[c-'A'][l-'A']) { // remove the edge c -> l
count[l-'A']--;
}
}
// 注意题目要求从最下面的框开始输出,所以头插字母
seq.insert(seq.begin(), c);
dfs(ans, seq, count, letters, graph);
// backtrack
seq.pop_front();
for (auto& l : letters) {
if (graph[c-'A'][l-'A']) {
count[l-'A']++;
}
}
}
}
}
}
int main() {
int height, width;
while (true) {
cin >> height >> width;
if (height==0 && width == 0) {
break;
}
vector<string> board(height);
unordered_set<char> Letters;
for (int i = 0; i < height; ++i) {
cin >> board[i];
for_each(board[i].begin(), board[i].end(), [&Letters](char c){
Letters.insert(c);
});
}
Letters.erase('.');
vector<Frame> frames(26);
// 由于frame的每个边都会至少有一个字母,扫描全图确定边界
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
char curLetter = board[i][j];
if (curLetter != '.') {
frames[curLetter-'A'].letter = curLetter;
frames[curLetter-'A'].x1 = min(frames[curLetter-'A'].x1, j);
frames[curLetter-'A'].x2 = max(frames[curLetter-'A'].x2, j);
frames[curLetter-'A'].y1 = min(frames[curLetter-'A'].y1, i);
frames[curLetter-'A'].y2 = max(frames[curLetter-'A'].y2, i);
}
}
}
vector<vector<bool>> graph(26, vector<bool>(26, false));
char curLetter;
for (auto& frame : frames) {
if (frame.letter == '.') {
continue;
}
// inspect up and down edges
for (int i = frame.x1; i <= frame.x2; ++i) {
curLetter = board[frame.y1][i];
if (curLetter != frame.letter) {
graph[curLetter - 'A'][frame.letter - 'A'] = true; // 构建一条从 curLetter -> frame.letter 的边
}
curLetter = board[frame.y2][i];
if (curLetter != frame.letter) {
graph[curLetter - 'A'][frame.letter - 'A'] = true;
}
}
// inspect left and right edges
for (int i = frame.y1; i <= frame.y2; ++i) {
curLetter = board[i][frame.x1];
if (curLetter != frame.letter) {
graph[curLetter - 'A'][frame.letter - 'A'] = true;
}
curLetter = board[i][frame.x2];
if (curLetter != frame.letter) {
graph[curLetter - 'A'][frame.letter - 'A'] = true;
}
}
}
// 入度记录
vector<int> count(26, 0);
for (auto c : Letters) {
for (int i = 0; i < 26; ++i) {
if (graph[i][c - 'A']) {
count[c-'A']++;
}
}
}
list<char> seq;
vector<string> answer;
dfs(answer, seq, count, Letters, graph);
// 按字典序输出
std::sort(answer.begin(), answer.end());
for (auto& ans : answer) {
cout << ans << endl;
}
}
return 0;
}