原题: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!