url:https://www.acwing.com/problem/content/description/189/
至于题解有好多,即枚举所有数,考虑将当前数字放入上升子序列当中还是下降子序列当中。
y总的代码中是
bool dfs(int depth, int u, int su, int sd)
{
// 如果上升序列个数 + 下降序列个数 > 总个数是上限,则回溯
if (su + sd > depth) return false;
if (u == n) return true;// 枚举放到上升子序列中的情况
...
if (dfs(depth, u + 1, su, sd)) return true;
...
if (dfs(depth, u + 1, su + 1, sd)) return true;// 枚举放到下降子序列中的情况
...
if (dfs(depth, u + 1, su, sd)) return true;
...
if (dfs(depth, u + 1, su, sd + 1)) return true;
}return false;
int main(){
...
int depth = 0;
while(!dfs(depth,0,su,sd)) depth ++; #depth即为最后的答案
...
}
这样还是稍微有点难理解的,因为这样操作,在dfs()函数里有许多情况可以早早return,不需要判断下去。
但是我们知道的是这道题的时间复杂度是非常大的,剪枝优化在于得到的答案是否大于之前一直在更新的答案,如果已经大于之前得出的答案,那么这条路就没必要走了。
因此如果把depth写在dfs()函数里,你会发现少了许多return语句,意即许多东西还是要进行判断的,而不能早早返回。当然我个人认为这样子会更好理解。
Python代码如下:
inp = lambda: list(map(int, input().split()))
n, = inp()
def dfs(u, step, up, down):
global ans, arr, n
if step >= ans:return False # 回溯条件
if u == n:
ans = min(ans, step)
return True
flag = True # 需要创建子序列
for i in range(len(up)):
if up[i] < arr[u]:# 剪枝操作
t = up[i] # 为复位做准备
up[i] = arr[u]
flag = False # 不需要新增子序列
dfs(u + 1, step, up, down)
up[i] = t
break
if flag: # 所有的上升子序列都不满足条件
up.append(arr[u])
dfs(u + 1, step+1, up, down)
up.pop()
flag = True
for i in range(len(down)):
if down[i] > arr[u]:
t = down[i]
down[i] = arr[u]
flag = False
dfs(u+1,step,up,down)
down[i] = t
break
if flag:
down.append(arr[u])
dfs(u+1,step+1,up,down)
down.pop()
return False
while n != 0:
ans = float('inf')
arr = inp()
dfs(0,0,[],[])
print(ans)
n, = inp()