POJ-1020 Anniversary Cake + Python(DFS)

原题:1020 -- Anniversary Cake

一 问题描述

对于一个大小为size*size的方形矩阵,现在用n个小方块将其填满。

要求:

1 n个方块均需被填入矩阵;

2 填放完毕之后,方形矩阵中无空位,即正好将方形矩阵填满。

详细描述见原题链接。

二 结题思路:DFS检测可行的一种方案

# 1 根据大蛋糕尺寸size,设置一个Size*Size大小的矩阵,并设置其初始值为0,用来存放小蛋糕。

# 2 对nums块小蛋糕从大到小排序,然后分别对每块小蛋糕进行放置处理。此处设置一个for循环,共循环nums次。

# 1.1 检测矩阵0元素所在的位置,作为放置当前小蛋糕的起始节点node

1.1.1 判断当前位置的行索引,是否能够放下当前的小蛋糕;

# 1.1.2 判断当前位置的列索引,是否能够放下当前的小蛋糕;

# 1.1.3 如果能放下,则将小蛋糕覆盖的全局矩阵self.new_data元素赋值为1,并返回;说明当前小蛋糕已经放置完毕,然后对下一块小蛋糕进行放置。

# 1.1.4 如果不能放下,则设置局部矩阵nnew_data当前的位置至矩阵边界之间的元素为-1,表明这些点不能用来放置当前的小蛋糕;然后查找其他0元素的位置,执行DFS搜索,继续查找可行的放置位置。

# 1.1.4.1 如果仍然不能有效放置,则返回False

# # 2 终止条件:

# 对于当前小蛋糕,如果能够有效放置,则终止当前的DFS,返回True;然后对下一块小蛋糕进行处理。

# 3 需要注意的时:

# 3.1 设置一个全局矩阵self.new_data,当能够有效放置小蛋糕时,将小蛋糕覆盖的区域填上1

# 3.2 在dfs子程序中,设置一个局部矩阵nnew_data,当前小蛋糕未能有效放置时,那么将当前坐标节点赋值为-1;然后查找其他潜在的放置点,进入DFS递归搜索。

# 4 循环执行完毕之后,检测全局矩阵中的元素是否全为1:是,则成功!

三 代码实现

# http://poj.org/problem?id=1020
# https://exp-blog.com/algorithm/poj-shi-ti-fen-lei/
# 参考资料:https://exp-blog.com/algorithm/poj/poj1020-anniversary-cake/

# ## 解题思路:DFS检测可行的一种方案
# 1 根据蛋糕尺寸size,设置一个Size*Size大小的矩阵,并设置其初始值为0,用来存放蛋糕。
# 2 对nums块蛋糕从大到小排序,然后分别对每块蛋糕进行处理。此处设置一个for循环,共循环nums次。
# 1.1 检测矩阵0元素所在的位置,作为放置当前蛋糕的起始节点node
# 1.1.1 判断当前位置的行索引,是否能够放下当前的蛋糕;
# 1.1.2 判断当前位置的列索引,是否能够放下当前的蛋糕;
# 1.1.3 如果能放下,则将蛋糕覆盖的全局矩阵self.new_data元素赋值为1,并返回;说明当前蛋糕已经放置完毕,然后对下一块蛋糕进行放置。
# 1.1.4 如果不能放下,则设置局部矩阵nnew_data当前的位置至矩阵边界之间的元素为-1,表明这些点不能用来放置当前的蛋糕;然后查找其他0元素的位置,执行DFS搜索,继续查找可行的放置位置。
# 1.1.4.1 如果仍然不能有效放置,则返回False

# # 2 终止条件:
# 对于当前蛋糕,如果能够有效放置,则终止当前的DFS,返回True;然后对下一块蛋糕进行处理。
# 3 需要注意的时:
# 3.1 设置一个全局矩阵self.new_data,当能够有效放置蛋糕时,将蛋糕覆盖的区域填上1
# 3.2 在dfs子程序中,设置一个局部矩阵nnew_data,当前蛋糕未能有效放置时,那么将当前坐标节点赋值为-1;然后查找其他潜在的放置点,进入DFS递归搜索。
# 4 循环执行完毕之后,检测全局矩阵中的元素是否全为1:是,则成功!

## 将数据转化为元素为0的矩阵
def proData(size):
    new_data = [[0]*size for i in range(size)]
    return new_data
## 获得元素为0的顶点坐标,并存储在队列中
def data2dict(new_data):
    dict_queue = []
    for i in range(size):
        for j in range(size):
            if new_data[i][j] ==0:
                str1 = str(i)+';'+str(j)
                dict_queue.append(str1)

    return dict_queue
## 判断元素是否都为1
def Result(data):
    sum = 0
    for i in range(size):
        for j in range(size):
            sum = int(data[i][j]) + sum
    if sum == size*size:
        return True
    else:
        return False

### DFS处理
class Solution:
    def DFS(self):
        # self.Flag = False ## 标记位,用于查询是否存在可行方案
        self.new_data = new_data
        for start in sorted(subData, reverse=True):  # 蛋糕降序排列
            self.dict_queue = data2dict(self.new_data)  # 矩阵中元素为0的点的队列集合
            for node in self.dict_queue: #对于每个可用的节点而言
                step = 1 # 记录执行的次数
                if self.dfs(node,self.new_data,start,step) == True: # 如果能放下,则跳出当前循环,执行下一次蛋糕放置。
                    break
        ## 判断,如果self.new_data所有元素均为1,则成功
        if Result(self.new_data):
            return 'KHOOOOB!'
        else:
            return 'HUTUTU!'
    def dfs(self,node,data,start,step):
        ### 转存矩阵数据
        nnew_data = []
        for ii in range(size):
            temp= []
            for jj in range(size):
                temp.append(data[ii][jj])
            nnew_data.append(temp)
        ###### 填充当前这个点
        #1 当前的节点坐标
        rr,cc = map(int,node.split(';'))
        ### 放置之后坐标范围
        new_rr = rr + start
        new_cc = cc + start
        #2 判断终止条件:
        # 当不超过行列索引时,填充当前蛋糕所覆盖的区域,赋值为-1
        if new_rr - 1 <= size - 1 and new_cc - 1 <= size - 1:
            # Flag = True
            for ii in range(rr, new_rr):
                for jj in range(cc, new_cc):
                    self.new_data[ii][jj] = 1
            return True
        #3 当不能填放时,标记所有不能填方的点
        if new_rr-1 > size -1: # 超过行索引
            ## 将相应的行全部填充为-1,表示这些行均不能放置当前的蛋糕块
            for index_r in range(rr,size):
                for index_c in range(size):
                    nnew_data[index_r][index_c] = -1
        if new_cc-1>size-1: #超过列索引
            ## 将相应的列全部填充为-1,表示这些列均不能放置当前的蛋糕块
            for index_c in range(cc,size):
                for index_r in range(size):
                    nnew_data[index_r][index_c] = -1
        #3.5 检测其他元素为0的点的顶点坐标,并进行DFS处理,查找是否可以填放蛋糕
        new_dict_queue = data2dict(nnew_data)  # 矩阵中元素为0的点的队列集合
        for new_node in new_dict_queue:
            if self.dfs(new_node,nnew_data,start,step+1):
                return True
        return False
## 迎接数据
## 总数
N = int(input().strip())
## 存储数据
data = []
size_date = []
nums_data = []
for i in range(N):
    temp = list(map(int,input().strip().split(' ')))
    size_date.append(temp[0])
    nums_data.append(temp[1])
    data.append(temp[2:])
print(data)
########## 开始处理
for case in range(N):
    ### 提取数据
    size = size_date[case]
    nums = nums_data[case]
    subData = data[case]
    ### 数据预处理
    new_data = proData(size)
    #### DFS处理
    test = Solution()
    ans = test.DFS()
    print(ans)



版本2:

import math
import collections

## 迎接数据
# 数据总数
N = int(input().strip())
data = []
size_data = []
n_data = []
for i in range(N):
    temp = list(map(int,input().strip().split(' ')))
    size_data.append(temp[0])
    n_data.append(temp[1])
    data.append(temp[2:])

## 数据转化
def sub2data(size):
    new_matric = [[0]*size for i in range(size)] # 全0方阵
    index = []
    for i in range(size):
        for j in range(size):
            str1 = str(i)+';'+str(j)
            index.append(str1)
    return index,new_matric
########3
# 查找元素为0的位置
def FindEmpty(new_matric):
    nodes = []
    for i in range(size):
        for j in range(size):
            if new_matric[i][j] == 0:
                nodes.append(str(i)+';'+str(j))
    return nodes
# 查找元素是否均为1
def Result(data):
    res = 0
    for i in range(size):
        for j in range(size):
            res = res + int(data[i][j])
    if res == size*size:
        return True
    else:
        return False

####
class Solutions:
    def DFS(self):
        ### 首先将小蛋糕排序
        #sort_data = subdata.sort(reverse=True)
        self.new_matric = new_matric
        print(new_matric)
        for cake_size in sorted(subdata,reverse=True):# 对从大到小的蛋糕排序
            # 查找元素为0的位置
            nodes = FindEmpty(self.new_matric)
            for node in nodes:#对每个空格位置进行考核
                ## 判断能否把当前的蛋糕存放起来
                if self.dfs(node,cake_size,self.new_matric) == True:
                    break
        return Result(self.new_matric)
    def dfs(self,node,cake_size,data):
        ## 传递数据
        new_data = []
        for i in range(size):
            temp = []
            for j in range(size):
                temp.append(data[i][j])
            new_data.append(temp)
        ## 
        ## 解析当前位置
        rr,cc = map(int, node.split(';'))
        ## 判断蛋糕覆盖区域是否越界
        new_rr = rr + cake_size -1;
        new_cc = cc + cake_size -1;
        if new_rr <= size -1 and new_cc <= size-1:#说明不越界
            # 更新元素值为1
            for ii in range(rr,new_rr+1):
                for jj in range(cc,new_cc+1):
                    self.new_matric[ii][jj] = 1
            return True
        
        ## 如果行越界
        if new_rr>size-1:
            for ii in range(rr,size):
                for jj in range(size):
                    new_data[ii][jj] = -1
        if new_cc>size-1:
            for jj in range(cc,size):
                for ii in range(size): #范围从0到size-1;不要写成range(1,size),因为此时的范围是1到size-1
                    new_data[ii][jj] = -1
        ## 继续处理
        ## 检测可行的存放位置
        new_nodes = FindEmpty(new_data)
        for new_node in new_nodes:
            if self.dfs(new_node,cake_size,new_data):
                return True
        # 无可行方案时,返回False
        return False

#############
# 开始处理
for case in range(N):
    subdata = data[case]
    size = size_data[case]
    n = n_data[case]
    ### 数据转化,空格+有效索引列表
    index,new_matric = sub2data(size)
    test = Solutions()
    ans = test.DFS()
    print(ans)
    

输入:

2
4 8 1 1 1 1 1 3 1 1
5 6 3 3 2 1 1 1

输出:

KHOOOOB!
HUTUTU!

POJ-1020 Anniversary Cake + Python(DFS)_第1张图片

你可能感兴趣的:(刷题,深度优先,python,算法)