有n个柱子,每个柱子有k个面,敲击后其本身及前后的柱子会顺时针旋转一定的角度度,问对任意一种初始状态下的柱子,应当如何敲击能够保证其都面对着特定的一面
pro = """
有n个柱子,每个柱子有k个面,敲击后其本身及前后的柱子会顺时针旋转一定的角度度,问对任意一种初始状态下的柱子,应当如何敲击能够保证其都面对着特定的一面
"""
import re
from pyscipopt import Model, quicksum
def case():
A, k, isEnd2End = [0, 0, 0, 1], 4, False
# A, k, isEnd2End = [0, 1, 2, 3], 4, False
# A, k, isEnd2End = [0, 0, 2, 3], 4, False
A, k, isEnd2End = [1, 1, 0, 0, 0], 2, False
A, k, isEnd2End = [1, 1, 0, 0, 1], 2, True
return A, k, isEnd2End
def IP(A, k, isEnd2End, timeLimit=100, isPrint=True):
# 建模求解
model = Model("IP")
n = len(A)
X = [model.addVar(vtype="I", name="X[%s]"%(i)) for i in range(n)]
B = [model.addVar(vtype="I", name="B[%s]"%(i)) for i in range(n)]
#击打次数最少
model.setObjective(quicksum(X[i] for i in range(n)), "minimize")
#变量内置约束
for i in range(n):
model.addCons(X[i] >= 0)
#每个柱子都面对特定的一面
if isEnd2End:
model.addCons(X[n-1] + X[0] + X[1] == k * B[0] - A[0])
model.addCons(X[n - 1] + X[n - 2] + X[0] == k * B[n - 1] - A[n - 1])
else:
model.addCons(X[0] + X[1] == k * B[0] - A[0])
model.addCons(X[n-1] + X[n-2] == k * B[n-1] - A[n-1])
for i in range(1, n-1):
model.addCons(X[i - 1] + X[i] + X[i + 1] == k * B[i] - A[i])
# 设置求解时间
model.setRealParam("limits/time", timeLimit)
model.hideOutput()
model.optimize()
if isPrint:
print("\ngap:", model.getGap())
X1 = [round(model.getVal(X[i])) for i in range(n)]
return X1
def resPrint(A, X, k, isEnd2End):
print("初始序列: {}".format(A))
print("每个柱子几个面: {}".format(k))
print("是否首尾相连: {}".format(isEnd2End))
print("击打序列: {}".format(X))
n = len(A)
A1 = [0 for i in range(n)]
if isEnd2End:
A1[0] = A[0] + X[n-1] + X[0] + X[1]
A1[n - 1] = A[n - 1] + X[n - 1] + X[n - 2] + X[0]
else:
A1[0] = A[0] + X[0] + X[1]
A1[n-1] = A[n-1] + X[n-1] + X[n-2]
for i in range(1, n-1):
A1[i] = A[i] + X[i-1] + X[i] + X[i+1]
print("终止序列: {}".format(A1))
if __name__ == '__main__':
A, k, isEnd2End = case()
X = IP(A, k, isEnd2End)
resPrint(A, X, k, isEnd2End)