求解一个约束优化问题

题目

在给定两个集合 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:BAy=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 yA,  xBf(x)=yxy 。求映射 f f f ,使得 ∑ y ∣ ∃ x ∈ B , f ( x ) = y y \sum_{y\mid \exists x\in B,f(x)=y}y yxB,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

输出结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值