回溯剪枝trick

lc638

dfs+memo

比"不买任何大礼包单买商品"和"买各个可用大礼包后再买剩余商品"的花费,找出满足购物需求的最低价格。

class Solution {

public:

// 不同的needs所需的价格

map<vector<int>, int> _cache;

int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs)

{

return dfs(needs, price, special);

}

int dfs(vector<int> needs, vector<int>& price, vector<vector<int>>& special) {

// 如果子问题已经计算过 直接返回

if (_cache[needs]) { return _cache[needs]; }

int ans = 0;

// 最弱的方式;不购买大礼包

for (int i = 0; i < needs.size(); i++) {

ans += needs[i] * price[i];

}

// 遍历每个礼包,购买它,看看是不是能获得更便宜的价格

for (int i = 0; i < special.size(); i++) {

vector<int> next = needs;

bool valid = true;

// 因为购买的数量需要正好是needs 所以大礼包的某个商品不能超过needs的商品数量

for (int item = 0; item < price.size(); item++) {

if (special[i][item] > needs[item]) {

valid = false;

break;

}

}

// 当前大礼包不符合要求 跳过

if (!valid) continue;

// 当前大礼包符合要求,用next数组记录买过大礼包之后还需要买多少商品

for (int item = 0; item < price.size(); item++) {

++next[item] -= special[i][item];++

}

++ans = min(ans, dfs(next, price, special) + special[i].back());++

}

// 更新cache

_cache[needs] = ans;

return ans;

}

};

lc473

先判断火柴总长度是否能分成4等份且无超长火柴

再用回溯尝试把每根火柴分配到正方形的四条边,看是否能让每条边长度都等于目标边长

++// 剪枝:避免重复探索相同长度火柴的无效分支
if (i > 0 && matchsticks[index] == matchsticks[index - 1] && !vis[index - 1]) {
continue;
++

class Solution {

public:

bool makesquare(vector<int>& matchsticks) {

int sum = 0;

for (int m : matchsticks) sum += m;

if (sum % 4 != 0) return false;

int target = sum / 4;

sort(matchsticks.rbegin(), matchsticks.rend());

for (int m : matchsticks) if (m > target) return false;

vector<int> edges(4, 0);

vector<bool> vis(matchsticks.size(), false); // 标记火柴是否已使用

return backtrack(matchsticks, edges, 0, target, vis);

}

bool backtrack(vector<int>& matchsticks, vector<int>& edges, int index, int target, vector<bool>& vis)

{

if (index == matchsticks.size()) return true;

for (int i = 0; i < 4; ++i) {

// 剪枝1:当前边放入火柴后长度不超过target

if (edges[i] + matchsticks[index] <= target) {

++// 剪枝2:避免重复探索相同长度火柴的无效分支
if (i > 0 && matchsticks[index] == matchsticks[index - 1] && !vis[index - 1]) {
continue;
++

}

++edges[i] += matchsticks[index];++

vis[index] = true;

if (backtrack(matchsticks, edges, ++index + 1,++ target, vis))

return true;

edges[i] -= matchsticks[index];

vis[index] = false;

}

// 剪枝3:当前边长度为0,后续边无需重复处理

if (edges[i] == 0) break;

}

return false;

}

};

相关推荐
咩咦几秒前
C++学习笔记21:日期类加减天数
c++·学习笔记·运算符重载·日期类·operator+·operator+=
努力努力再努力wz2 分钟前
【QT入门系列】QWidget 六大常用属性详解:windowOpacity、cursor、font、focus、toolTip 与 styleSheet
android·开发语言·数据结构·c++·qt·mysql·算法
少司府3 分钟前
Tools相关:深入浅出学Git
大数据·c++·git·gitee·github·仓库·分支
神仙别闹4 分钟前
基于MFC(C++)实现(界面)学委作业管理系统
开发语言·c++·mfc
艾莉丝努力练剑7 分钟前
【Linux网络】Linux 网络编程:HTTP(三)HTTP 协议原理
linux·运维·服务器·网络·c++·http
字节高级特工12 分钟前
C++11(一) 革新:右值引用与移动语义
java·开发语言·c++·人工智能·后端
叶之香15 分钟前
一次 Kingston U 盘重定向中获取 Device Descriptor 超时问题排查
c++·windows·visual studio
UestcXiye15 分钟前
GoogleTest 使用指南 | 单元覆盖率分析
c++·单元测试·googletest
王老师青少年编程19 分钟前
csp信奥赛C++高频考点专项训练之前缀和&差分 --【一维前缀和】:“非常男女”计划
c++·前缀和·csp·高频考点·信奥赛·“非常男女”计划
故事和你9122 分钟前
洛谷-【图论2-4】连通性问题2
开发语言·数据结构·c++·算法·动态规划·图论