WOJ 110 Frame Stacking-所有拓扑排序序列

这是一篇关于解决WOJ 110题目的博客,通过图论和回溯法(深度优先搜索)来确定框的堆叠顺序。博主首先介绍了题目的背景,然后详细讲解了如何构建图并进行拓扑排序,最后给出了C++实现的代码示例。
摘要由CSDN通过智能技术生成

题目

题目链接
给出几个互相交错的框,输出交叠的顺序,根据题意,每个由字母组成的框(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值