一道经典的深搜题,以为自己可以轻松解决的,结果犯了很多细节上的错误,都记录下来作个警示吧。
题目大意是用+-*/任意组合5个数(每种符号使用次数不限,除法要求只能是整除,每个数字只能用一次,可以不用完全部数字),使得运算res为小于等于给定target的最大值
思路是穷举5个数的排列方式,挑选另一个数与它进行叠加(+-*/),
深搜进去变成4个数,再穷举4个数的排列方式……
深搜进去变成3个数……
直到最后只剩一个数,也就是运算结果
唉这学期太忙,化在算法课上的时间好少,题都不会刷了,要好好反思一下了。
犯错点用数字标记出来了。
#include <iostream>
#include <algorithm>
using namespace std;
int num[5];
int target;
int finalres;
bool get;
void dfs(int* num, int level){
if (num[level] > finalres && num[level] <= target)//①
finalres = num[level];
if (finalres == target){
get = true;
return;
}
if (level == 4 || get)//②
return; int tmp[5];
for (int i = level; i < 5; i++){
for (int j = i + 1; j < 5; j++){
int a = num[i], b = num[j], count = 4;
for (int k = 4; k >= level; k--){//③
if (k == i || k == j)
continue;
tmp[count--] = num[k];
}
tmp[level + 1] = a + b;
dfs(tmp, level + 1);
tmp[level + 1] = a - b;
dfs(tmp, level + 1);
tmp[level + 1] = b - a;
dfs(tmp, level + 1);
tmp[level + 1] = a * b;
dfs(tmp, level + 1);
if (a!= 0 && b != 0 && a % b == 0){//④
tmp[level + 1] = a / b;
dfs(tmp, level + 1);
}
else if (a!= 0 && b != 0 && b % a == 0){
tmp[level + 1] = b / a;
dfs(tmp, level + 1);
}
}
}
}
int main(){
int N, T;
cin >> N;
while (N--){
for (int i = 0; i < 5; i++){
cin >> num[i];
}
cin >> target;
get = false;
finalres = -2000000000;//⑤
dfs(num, 0);
cout << finalres << endl;
}
return 0;
}
①这个if必须放在最前面(否则若把第3个if提到首,若到level4时找到了答案,根本没对finalres赋值就return掉了),下面两个if的顺序无所谓,区别只在get没有而已,只是为了早一步结束不必要的搜索,但是并不影响结果
②当num[level]>target或是<0时不能return,因为有可能通过后面的运算再把数值拉回到范围之内,下方算a-b和b-a两种减法也是同理
③复制num数组方便传入,这种内存问题自己犯过好多次了,有强迫症希望能少用空间就少用空间,这种习惯挺好但是自己老是死在这上面,想对内存空间重复利用就必须要记得保护现场和恢复现场啊,像这一题用这种实现方法的话,这样大量开辟栈空间是不可避免的了
④题目中只允许整除,注意下面要是elseif,防止a==b的情况算两次
⑤虽然题目说target是在[0,1000],但是这句改成-1都WA,估计是有负数输入的,究竟是num[i]还是target就不得而知了