AcWing 导弹防御系统 Python代码

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()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值