Python数据结构与算法(poj):P01084——正方形破坏者

OpenJudge - 01084:正方形破坏者

        很好的一道搜索题,题目的要求很简单(至少听上去是这样的),用火柴棒拼成一个n\times n的正方形(n\leq 5),事先拆掉了一些火柴棒,那么至少还需要去掉多少根火柴棒才能使拼出的图形中没有正方形(摧毁所有正方形)?

        数据不算大,显然使用dfs。倘若讨论每根火柴是否已被拿走,没被拿走就拿走,同时对当前状态的正方形个数进行计数,与之前的进行比较从而达到剪枝的目的,这样做,哪怕后面使用位运算存储累计拿走火柴棒的状态,仍然会超时(也有可能超内存)。

        于是,我们改变思路,我们还是需要看火柴是否被拿走,但我们从正方形的角度进行考虑,这样计数时的复杂度就会由O(n^4)降低到O(n^3),然而仍然会超时。

        注意到,尽管我们会将此时拿走火柴棒的次数与全局变量ans(最后输出的结果)进行比较,但很多时候当前状态已经显然会超出ans,因此我们使用IDA*算法(我也是现学的,感觉挺好理解,不明白的可以看这个:IDA* - OI Wiki (oi-wiki.org))。

        使用该算法时,我们首先定义一个估价函数,用于进行判断当前状态还需要的最少火柴棒数目(准确地说,可能会比实际达到的数目还要少,但剪枝的效率极高)。

        再之后,我们只需要进行正常的dfs了,同时添加一些剪枝,比如一个正方形删掉任意边都搜不出来,那么整个状态就可以扔掉;比如我们定义一个found布尔变量,一旦找到,那么就结束搜索;比如我们使用while循环,并定义一个limit变量,最初存储估价函数的值,之后搜索,搜不到就加一,搜到了就可以输出并结束进程了。

说了这么多可能也没有说明白,看看代码叭~

import copy
import sys
sys.setrecursionlimit(1 << 30)
found = False

def check1(x, tmp):
    for y in graph[x]:
        if tmp[y]:
            return False
    return True

def check2(x):
    for y in graph[x]:
        if judge[y]:
            return False
    return True

def estimate():
    cnt = 0
    tmp = copy.deepcopy(judge)
    for x in range(1, total+1):
        if check1(x, tmp):
            cnt += 1
            for u in graph[x]:
                tmp[u] = True
    return cnt

def dfs(t):
    global found
    if t + estimate() > limit:
        return
    for x in range(1, total+1):
        if check2(x):
            for y in graph[x]:
                judge[y] = True
                dfs(t+1)
                judge[y] = False
                if found:
                    return
            return
    found = True

for _ in range(int(input())):
    n = int(input())
    lst = list(map(int, input().split()))
    d, m, nums, total = 2*n+1, lst[0], lst[1:], 0
    graph = {}
    for i in range(n):
        for j in range(n):
            for k in range(1, n+1):
                if i+k <= n and j+k <= n:
                    total += 1
                    graph[total] = []
                    for p in range(1, k+1):
                        graph[total] += [d*i+j+p, d*(i+p)+j-n, d*(i+p)+j-n+k, d*(i+k)+j+p]
    judge = [False for _ in range(2*n*(n+1)+1)]
    for num in nums:
        judge[num] = True
    limit = estimate()
    found = False
    while True:
        dfs(0)
        if found:
            print(limit)
            break
        limit += 1

  • 23
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值