今天有 \(n\) 個量杯。你想要用這幾個量杯,
經過下面給定的三種操作,來讓最後某個量杯中有 \(t\) 的水量。
把量杯裝滿水
把量杯中的水倒到另外一個量杯中
把量杯中的水倒光
就是窮舉法
另外,要讓程式紀錄一種組合的資訊
建立一個陣列來存初始組合狀態,
以及由這個初始狀態窮舉出的組合狀態。
# iterate data
data = list()
# the data of a combination
class Combination:
def __init__(self, init_father_index: int, init_step: int, init_list: list):
self.father_index = init_father_index
self.step = init_step
self.cups_volume = init_list
\(self.father\_index\)
用於步驟回朔,註明:「這個組合是哪個組合的下一步」
其中哪個組合(父節點)在 \(data\) 中的位置
\(self.step\)
註明:這個組合的最少步驟數
\(self.cups\_volume\)
註明:這個組合中,每個量杯各自的水量
data = [comb0]
# initialize first combination
data.append(Combination(0, 0, [0] * n))
(父節點為自己、步驟為0、各量杯水量都為零)
# try 1: fill cup to maximum volume
for cup_index in range(n):
# if the cup is already full, then skip this step
if data[cur_p].cups_volume[cup_index] == cup_max[cup_index]:
continue
new_comb = data[cur_p].cups_volume.copy()
# fill the cup of index 'cup_index' to its maximum volume
new_comb[cup_index] = cup_max[cup_index]
find = check_and_manipulate(cur_p, data[cur_p].step + 1, new_comb)
if find:
break
# try 2: pour water from cup a to b
for a_index in range(n):
for b_index in range(n):
# situation 1: if a-cup is b-cup, then skip this step
# situation 2: if a-cup is empty, then skip this step
# situation 3: if b-cup is full, then skip this step
if a_index == b_index \
or data[cur_p].cups_volume[a_index] == 0 \
or data[cur_p].cups_volume[b_index] == cup_max[b_index]:
continue
new_comb = data[cur_p].cups_volume.copy()
# criterion: delta value <= a-cup
# situation 1: if a-cup currently has more water than b_max - b-cup,
# then the delta value is b_max - b-cup
# situation 2: if a-cup currently has less water than b_max - b-cup,
# then the delta value is just a-cup itself
delta_volume = min(cup_max[b_index] - new_comb[b_index], new_comb[a_index])
new_comb[a_index] -= delta_volume
new_comb[b_index] += delta_volume
find = check_and_manipulate(cur_p, data[cur_p].step + 1, new_comb)
if find:
break
if find:
break
# try 3: pour the water out of the cup
for cup_index in range(n):
# if the cup is empty, then skip this step
if data[cur_p].cups_volume[cup_index] == 0:
continue
new_comb = data[cur_p].cups_volume.copy()
# pour the water out of the cup of index 'cup_index'
new_comb[cup_index] = 0
find = check_and_manipulate(cur_p, data[cur_p].step + 1, new_comb)
if find:
break
如果在,那就直接將答案設為 \(comb1\),
將其加進 \(data\) 中,並跳過之後的所有窮舉。
comb1
data
data = [comb0, comb1]
# the needed volume is already in the new combination
if t in detect_comb:
ans = Combination(father_ind, needed_step, new_comb)
return True
comb1
❌
comb1
data
data = [comb0, comb1]
# the combination is already in the data
if detect_comb in [cups_data.cups_volume for cups_data in data]:
return False
# if two former test failed, that means this is a new combination
data.append(Combination(father_ind, needed_step, new_comb))
return False
while cur_p < len(data):
\(cur\_p\) : 目前所在位置
扣得
print('--> Programed and run by phantom0174 <--')
# cup count
n = int(input('請輸入杯子的個數><\n'))
# needed volume
t = int(input('請輸入你想要的水量><\n'))
# cup max volume
cup_max = list(input('請輸入各杯子的最大容量>< (要以空格隔開)\n').split(' '))
cup_max = list(map(int, cup_max))
# current pop index
cur_p = int(0)
# the data of a combination
class Combination:
def __init__(self, init_father_index: int, init_step: int, init_list: list):
self.father_index = init_father_index
self.step = init_step
self.cups_volume = init_list
# answer object
ans = Combination(0, 0, list())
# iterate data
data = list()
# initialize first combination
data.append(Combination(0, 0, [0] * n))
# the function for status checking
# if we find the answer, return True; otherwise, return False
def check_and_manipulate(father_ind, needed_step, detect_comb: list) -> bool:
global data, ans
# the needed volume is already in the new combination
if t in detect_comb:
ans = Combination(father_ind, needed_step, new_comb)
return True
# the combination is already in the data
if detect_comb in [cups_data.cups_volume for cups_data in data]:
return False
# if two former test failed, that means this is a new combination
data.append(Combination(father_ind, needed_step, new_comb))
return False
# main program
# initialize find status, which is equivalent to 'flag'
find = bool(False)
while cur_p < len(data):
print(f'Searching... ({cur_p}/{len(data) - 1})')
# try 1: fill cup to maximum volume
for cup_index in range(n):
# if the cup is already full, then skip this step
if data[cur_p].cups_volume[cup_index] == cup_max[cup_index]:
continue
new_comb = data[cur_p].cups_volume.copy()
# fill the cup of index 'cup_index' to its maximum volume
new_comb[cup_index] = cup_max[cup_index]
find = check_and_manipulate(cur_p, data[cur_p].step + 1, new_comb)
if find:
break
if find:
break
# try 2: pour water from cup a to b
for a_index in range(n):
for b_index in range(n):
# situation 1: if a-cup is b-cup, then skip this step
# situation 2: if a-cup is empty, then skip this step
# situation 3: if b-cup is full, then skip this step
if a_index == b_index \
or data[cur_p].cups_volume[a_index] == 0 \
or data[cur_p].cups_volume[b_index] == cup_max[b_index]:
continue
new_comb = data[cur_p].cups_volume.copy()
# criterion: delta value <= a-cup
# situation 1: if a-cup currently has more water than b_max - b-cup,
# then the delta value is b_max - b-cup
# situation 2: if a-cup currently has less water than b_max - b-cup,
# then the delta value is just a-cup itself
delta_volume = min(cup_max[b_index] - new_comb[b_index], new_comb[a_index])
new_comb[a_index] -= delta_volume
new_comb[b_index] += delta_volume
find = check_and_manipulate(cur_p, data[cur_p].step + 1, new_comb)
if find:
break
if find:
break
if find:
break
# try 3: pour the water out of the cup
for cup_index in range(n):
# if the cup is empty, then skip this step
if data[cur_p].cups_volume[cup_index] == 0:
continue
new_comb = data[cur_p].cups_volume.copy()
# pour the water out of the cup of index 'cup_index'
new_comb[cup_index] = 0
find = check_and_manipulate(cur_p, data[cur_p].step + 1, new_comb)
if find:
break
if find:
break
cur_p += 1
if not find:
print('不要為難我了qwq, 這是不可能的任務')
else:
print(f'恭喜!\\^~^ 你只要 {ans.step} 步就可以得到 {t} 的水量!')
step_list = list()
step_list.append(ans.cups_volume)
# initialize current father_index to search
father_index = ans.father_index
# get the cups_volume data from father_index, and update the next father_index
while father_index != 0:
step_list.append(data[father_index].cups_volume)
father_index = data[father_index].father_index
# because we're searching from back, we'll need to reverse the step logs
step_list.reverse()
print('以下是步驟!')
for step in step_list:
print(step)