Day32 backtracking 332.重新安排行程 51. N皇后 37. 解数独

2024/5/19 Day32 backtracking 332.重新安排行程 51. N皇后 37. 解数独

332.重新安排行程

题目链接 332
给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。

所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。

例如,行程 [“JFK”, “LGA”] 与 [“JFK”, “LGB”] 相比就更小,排序更靠前。
假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。

Container MAP

template<
    class Key,
    class T,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<std::pair<const Key, T>>
> class map;

默认排序存储

访问修改

pair<const string, int>& target : targets[result[result.size() - 1]]

for (map<string, int>::iterator it =  targets[result[result.size() - 1]].begin(); it !=  targets[result[result.size() - 1]].end(); it ++)

这里iterator 可以直接访问和修改map的第二个参数 it->second

想要拿出来pair<string, int>, 需要*it,如果不加 *

no known conversion from 'map<string, int>::iterator' (aka '_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char>>, int>>') to 'value_type' (aka 'std::pair<std::basic_string<char>, int>') for 1st argument

使用map的解法

map 第一种遍历写法

class Solution {
public:
    unordered_map<string, map<string, int> > flights;
    int ticketCnt;
    bool backtrack(vector<string>& res) {
        if (res.size() == ticketCnt +1) return true;
        for(pair<const string, int> &flight : flights[res[res.size() - 1]]) {
            if (flight.second > 0) {
                res.push_back(flight.first);
                flight.second --;
                if (backtrack(res)) return true;
                res.pop_back();
                flight.second ++;
            }
        }
        return false;
    }
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        ticketCnt = tickets.size();
        vector<string> res;
        res.push_back("JFK");
        for (vector<string> ticket : tickets) {
            flights[ticket[0]][ticket[1]] ++;
        }
        backtrack(res);
        return res;
    }
};

map第二种遍历写法

for(map<string, int> :: iterator it = flights[res[res.size()-1]].begin(); it != flights[res[res.size()-1]].end(); it++) {
    if (it -> second > 0) {
        res.push_back(it -> first);
        it -> second --;
        if (backtrack(res)) return true;
        res.pop_back();
        it -> second ++;
    }
}        

改变参数传递

class Solution {
public:
    unordered_map<string, map<string, int> > flights;
    int ticketCnt;
    vector<string> res;
    bool backtrack(string airport) {
        if (res.size() == ticketCnt +1) return true;
        for(map<string, int> :: iterator it = flights[airport].begin(); it != flights[airport].end(); it++) {
            if (it -> second > 0) {
                res.push_back(it -> first);
                it -> second --;
                if (backtrack(it->first)) return true;
                res.pop_back();
                it -> second ++;
            }
        }
        return false;
    }
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        ticketCnt = tickets.size();
        res.push_back("JFK");
        for (vector<string> ticket : tickets) {
            flights[ticket[0]][ticket[1]] ++;
        }
        backtrack("JFK");
        return res;
    }
};

Greedy的解法

思路及算法

Hierholzer 算法用于在连通图中寻找欧拉路径,其流程如下:

  1. 从起点出发,进行深度优先搜索。

  2. 每次沿着某条边从某个顶点移动到另外一个顶点的时候,都需要删除这条边。

  3. 如果没有可移动的路径,则将所在节点加入到栈中,并返回。

这样就能保证我们可以「一笔画」地走完所有边,最终的栈中逆序地保存了「一笔画」的结果。我们只要将栈中的内容反转,即可得到答案。

作者:力扣官方题解
链接:https://leetcode.cn/problems/reconstruct-itinerary/solutions/389885/zhong-xin-an-pai-xing-cheng-by-leetcode-solution/

回顾一下priority_Queue的用法

class Solution {
public:
    class cmp {
        public:
        cmp() {}
        bool operator() (const std::string& a, const std::string& b) {
            return a > b;
            //小顶堆
        }
    };
    unordered_map<string, priority_queue<string, vector<string>, cmp> > flights;

    vector<string> res;
    void greedy (string airport){
        while(! flights[airport].empty()) {
            string temp = flights[airport].top();
            flights[airport].pop();
            greedy(temp);
        }
        res.push_back(airport);       
    }
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        for (vector<string> ticket : tickets) {
            flights[ticket[0]].push(ticket[1]);
        }
        greedy("JFK");
        reverse(res.begin(), res.end());
        return res;
    }
};

51. N皇后

题目链接 51
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

第一次提交-回溯

这里 i-row确定了唯一一个左斜线
i+row 确定了唯一一个右斜线

class Solution {
public:
    vector<vector<string>> result;
    vector<string> map;
    unordered_set<int> col;
    unordered_set<int> left;
    unordered_set<int> right;
    int N;
    void dfs(int row) {
        if (row > N) {
            result.push_back(map);
            return;
        }
        string temp = "";
        for (int j = 1; j <= N; j++) {
            if (col.count(j))
                continue;
            if (left.count(j + row))
                continue;
            if (right.count(j - row))
                continue;
            col.insert(j);
            left.insert(j + row);
            right.insert(j - row);
            string temp = "";
            for (int i = 1; i <= N; i++) {
                if (i == j) {
                    temp += 'Q';
                    continue;
                }
                temp += '.';
            }
            map.push_back(temp);
            dfs(row + 1);
            map.pop_back();
            col.erase(j);
            left.erase(j + row);
            right.erase(j - row);
        }
    }
    vector<vector<string>> solveNQueens(int n) {
        N = n;
        dfs(1);
        return result;
    }
};

整理代码结构清晰

哈希表用数组,超级提速

注意数组如何初始化,如何传递参数

class Solution {
public:
    int N;
    vector<vector<string>> res;
    vector<string> path;
    void backtrack(int row, bool* left, bool* right, bool*col) {
        if (row == N) {
            res.push_back(path);
            return;
        }
        for (int i = 0; i < N ; i++) {
            if (left[i-row + N] || col[i] || right[i - N + row + N]) continue;
            string level = "";
            for (int j = 0; j < N; j++) {
                if (j == i) level.push_back('Q');
                else level.push_back('.');
            }
            path.push_back(level);
            left[i-row + N] = true;
            col[i] = true;
            right[i - N + row + N] = true;
            backtrack(row + 1, left, right, col);
            path.pop_back();
            left[i-row + N] = false;
            col[i] = false;
            right[i - N + row + N] = false;
        }
    }

    vector<vector<string>> solveNQueens(int n) {
        N = n;
        bool left[2*n] ;
        bool right[2*n];
        bool col[n];
        memset( left, false, sizeof(left));
        memset( right, false, sizeof(right));
        memset( col, false, sizeof(col));
        backtrack(0, left, right, col);
        return res;
    }
};

随想录 思路相近,技巧上没有我的方法好

37. 解数独

第一次提交

class Solution {
public:
    unordered_set <char> row[9];
    unordered_set <char> col[9];
    unordered_set <char> block[9];
    vector <int> empty;
    bool stop = false;
    void backtrack( vector< vector <char> >& board, int now) {
        if(now == empty.size()) {
            stop = true;
            return;
        }
        int i = empty[now]/9, j = empty[now] % 9, index = ((int)i/3) * 3 + (int)j/3;
        for (char ch = '1'; ch <= '9'; ch++) {
            if (row[i].count(ch) || col[j].count(ch) || block[index].count(ch)) continue;
            row[i].insert(ch);
            col[j].insert(ch);
            block[index].insert(ch);
            board[i][j] = ch;
            backtrack(board, now+1);
            if (stop) return;
            row[i].erase(ch);
            col[j].erase(ch);
            block[index].erase(ch);
            board[i][j] = '.';
        }        

    }
    void solveSudoku(vector<vector<char>>& board) {
        //init
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] == '.') {
                    empty.push_back(9*i + j);
                    continue;
                } 
                int index = ((int)i/3) * 3 + (int)j/3;
                row[i].insert(board[i][j]);
                col[j].insert(board[i][j]);
                block[index].insert(board[i][j]);
            }
        }
        backtrack(board, 0);
    }
};

理解了index之后就很平庸了

回溯总结

随想录

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MATLAB是一种强大的数值计算和图形处理环境,它非常适合编写算法和解决数学问题,包括解决数问题。在MATLAB中,你可以利用其丰富的矩阵操作和逻辑控制结构来设计一个解数的程序。以下是一个简要的步骤和思路: 1. **定义数的表示**:数可以用一个9x9的矩阵来表示,其中0表示空白格,1到9表示数字,1-9的数组表示可能的数字。 2. **读取或生成数题目**:可以从文件、用户输入或预定义的测试数据开始。 3. **初始化**:创建一个解决方案矩阵,并用初始数字填充已知的部分。 4. **递归搜索算法**: - 使用回溯法(backtracking)是常见的方法,从空格开始尝试填入数字。 - 对每个空格进行循环,尝试填入1-9中的每一个数字。 - 检查填入后是否符合数规则(每一行、每一列、每个宫格都不能有重复的数字)。 - 如果当前填入合法,递归检查下一行;如果不合法,回溯并尝试下一个数字。 5. **解决过程优化**: - 可以使用启发式策略(如最小的候选数优先),提高搜索效率。 - 利用MATLAB的并行计算能力,对部分步骤进行并行化,加速求解。 6. **结果验证**:将解出的矩阵与标准的数解对比,确保正确性。 **相关问题**: 1. 如何在MATLAB中实现回溯法? 2. 数的启发式策略有哪些可以在MATLAB中应用? 3. 怎样利用MATLAB的并行计算特性加速解数

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值