题目
在给定两个集合 A A A 和 B B B 。集合的元素都是大于 0 0 0 的实数。假设 A A A 有 m m m 个元素, B B B 有 n n n 个元素。将 B B B的每个元素映射到 A A A 的某个元素,可以多对一映射。假设映射为 f : B → A , y = f ( x ) f:B \rightarrow A,y=f(x) f:B→A,y=f(x) 。要求映射 f f f 满足: ∀ y ∈ A , ∑ x ∈ B ∣ f ( x ) = y x ≤ y \forall y \in A ,\ \ \sum_{x\in B\mid f(x)=y}x \leq y ∀y∈A, ∑x∈B∣f(x)=yx≤y 。求映射 f f f ,使得 ∑ y ∣ ∃ x ∈ B , f ( x ) = y y \sum_{y\mid \exists x\in B,f(x)=y}y ∑y∣∃x∈B,f(x)=yy 最小。
输入
输入文件为input.txt,共4行,第一行为A的元素个数m,第2行为m个值,用英文逗号隔开,代表A的元素,第3行为B的元素个数n,第4行为n个值,用英文逗号隔开,代表B的元素。m和n的最大值200。
例如输入文件:
4
3.5, 6, 9.2,10
3
1, 2, 4.5
方法
深度搜索,CSP回溯
模拟退火 🔥 🔥 🔥
思路
写着写着博客,发现看错题了,又搭进去了一个小时QAQ
主要的核心思想在于怎么退火,感觉这道题本来就应该是CSP回溯,非得用模拟退火,想来想去,只有映射个数的修改了……但总感觉写得像蒙特卡洛模拟……
文档读取
def read():
global m,n,A,B,alpha,T0,Tf,T,Cycle,SEQA,SEQB,f,ans,f_ans,SUM
with open('input.txt','r') as ff:
m = int(eval(ff.readline().strip()))
A = list(np.array(ff.readline().strip('\r\n').split(','),dtype=float))
n = int(eval(ff.readline().strip()))
B = list(np.array(ff.readline().strip('\r\n').split(','),dtype=float))
初始化,起初约束这里读错题了,是所有的 x x x 之和要小于 y y y ,而不是所有的 x x x 都小于 y y y
# 初始化
def init():
global m,n,A,B,alpha,T0,Tf,T,Cycle,SEQA,SEQB,f,ans,f_ans,SUM
T = T0
SUM = list(np.zeros(m+1))
# print(T)
for k in SEQB:
while(True): # 满足约束
temp = random.randint(1,m)
if B[k-1] + SUM[temp] <= A[temp-1]:
f[k] = temp
SUM[temp] += B[k-1]
break
修改,即修改映射,有点像蒙特卡洛模拟……
# 修改
def Change():
global m,n,A,B,alpha,T0,Tf,T,Cycle,SEQA,SEQB,f,ans,f_ans,SUM
newdict = deepcopy(f)
num = min(T*random.random(),n) # 修改映射的个数
num = int(num+0.5)
list = random.sample(SEQB,num) # num个不重复的x,修改映射f(x)
for k in list:
while(True): # 满足约束
temp = random.randint(1,m)
if B[k-1] + SUM[temp] <= A[temp-1]:
SUM[f[k]] -= B[k-1]
f[k] = temp
SUM[temp] += B[k-1]
break
return newdict
目标函数,简单求和罢了,注意下标,注意映射(我这里使用的映射是 索引 → \rightarrow → 索引)
# 目标函数
def AimFunction(dic): # dic字典 (映射函数)
global m,n,A,B,alpha,T0,Tf,T,Cycle,SEQA,SEQB,f,ans,f_ans,SUM
L = []
for k in SEQB:
L.append(dic[k])
L = list(set(L))
sum = 0
for i in L:
sum += A[i-1]
return sum
判断,这里是退火的板子,看看模拟退火算法就了解了
# 判断
def Check(newvalue,oldvalue):
global m,n,A,B,alpha,T0,Tf,T,Cycle,SEQA,SEQB,f,ans,f_ans,SUM
if newvalue <= oldvalue:
return 1
else:
p = exp((oldvalue-newvalue)/T)
if random.random() < p :
return 1
else:
return 0
写函数
def write():
global m,n,A,B,alpha,T0,Tf,T,Cycle,SEQA,SEQB,f,ans,f_ans,SUM
# print(f_ans)
with open('output.txt','w') as ff:
for i in SEQB:
ff.write(str(B[i-1])+','+str(f_ans[i])+','+str(A[f_ans[i]-1])+'\n')
主函数
def run():
global m,n,A,B,alpha,T0,Tf,T,Cycle,SEQA,SEQB,f,ans,f_ans,SUM
read()
SEQB = [i for i in range(1,n+1)] # 下标1开始
SEQA = [i for i in range(1,m+1)]
for i in range(Cycle):
init()
# print(f)
oldvalue = AimFunction(f)
if ans > oldvalue:
ans = oldvalue
f_ans = deepcopy(f)
while T > Tf:
newdict = Change()
newvalue = AimFunction(newdict)
if ans > newvalue:
ans = newvalue
f_ans = deepcopy(newdict)
if Check(newvalue,oldvalue):
f = deepcopy(newdict)
oldvalue = newvalue
T = T*alpha
# print(ans)
# print(f_ans)
write()
乱糟糟的,全局变量自己加上吧。。(Don’t have the same variable names)