A*算法解12硬币问题

12硬币问题 python源码 可拓展

有12个硬币,其中有一个假币,其重量未知,称量三次就可找出假币并知道其重量。可拓展,
利用A*算法求解。代码如下

#%%
import copy
import queue
#状态定义和目标状态
#五个位置分别代表,没经过称重硬币数,,可能假币较轻,可能假币较重,已知是真币个数,剩余称重次数。
# Goal1=[0,1,0,11,0]
# Gaol2=[0,0,1,11,0]
node=[12,0,0,0,3]#lhs,ls,hs,s,t
str_key={
    'lhs':0,
    'ls':1,
    'hs':2,
    's':3,
    't':4
}
coin_weight=[0,1,1,1,0,1,1,1,1,1,1,1,1]#硬币从下标1开始到12的重量。
coin_status=['lhs','lhs','lhs','lhs','lhs','lhs','lhs','lhs','lhs','lhs','lhs','lhs','lhs']#初始状态
#%%
def h(node):#[lhs,ls,hs,s,t] ,评价函数
    return sum(node[:3]) -1
def isGoal(node):
    if node[0]==0 and  node[3]==11:
        return  True
    else :
        return False
#%%
def pikup(coin_status,left,right):#从当前状态nownode中取出left:[lhs1,ls1,hs1,s1]放在天平左边,取出right:[lhs2,ls2,hs2,s2]方右边
    left_sum=0#左天平重量
    left_select=[]
    right_sum=0#左天平重量
    right_select=[]
    for coin,stat in enumerate(coin_status[1:]):
        coin+=1
        # print(coin)
        if stat =='lhs':
            if left[0]>0:
                left[0]-=1
                left_sum+= coin_weight[coin]
                left_select.append(coin)
            else:
                if right[0]>0:
                    right[0]-=1
                    right_sum+= coin_weight[coin]
                    right_select.append(coin)
        elif stat=='ls':
            if left[1]>0:
                left[1]-=1
                left_sum+= coin_weight[coin]
                left_select.append(coin)
            else:
                if right[1]>0:
                    right[1]-=1
                    right_sum+= coin_weight[coin]
                    right_select.append(coin)
        elif stat=='hs':
            if left[2]>0:
                left[2]-=1
                left_sum+= coin_weight[coin]
                left_select.append(coin)
            else:
                if right[2]>0:
                    right[2]-=1
                    right_sum+= coin_weight[coin]
                    right_select.append(coin)
        else:
            if left[3]>0:
                left[3]-=1
                left_sum+= coin_weight[coin]
                left_select.append(coin)
            else:
                if right[3]>0:
                    right[3]-=1
                    right_sum+= coin_weight[coin]
                    right_select.append(coin)
    if left_sum==right_sum:
        return 0,[left_select,right_select]
    elif left_sum>right_sum:
         return -1,[left_select,right_select]
    else:
         return 1,[left_select,right_select]#返回左右天平状态,和所选的cion

#%%
# temper,select=pikup([4,0,0,0],[4,0,0,0])
# print(temper,select)
#%%
def AStar(node,coin_status_in,left,right):#对当前选取,返回选取后的
    temp_node=copy.deepcopy(node)
    left_copy=copy.deepcopy(left)
    right_copy=copy.deepcopy(right)
    coin_status=copy.deepcopy(coin_status_in)
    # print(node)
    # print(coin_status)
    temper,select=pikup(coin_status,left_copy,right_copy)#选取一次经过天平,状态,select:具体选的硬币
    # print(temper,select)
    # if sum(left)!=len(select[0]) or sum(right)!=len(select[1]):
    #     print("pick up error")
    #     print(left)
    #     print(select[0])
    #     print(right)
    #     print(select[1])
    if temper==0:#天平左右平等,选取的所有硬币都为真
        for item in select:
            for j in item:
                if coin_status[j]=='lhs':
                    temp_node[0]-=1
                elif coin_status[j]=='ls':
                    temp_node[1]-=1
                elif coin_status[j]=='hs':
                    temp_node[2]-=1
                if coin_status[j]!='s':
                    temp_node[3]+=1
                coin_status[j]='s'
        temp_node[4]-=1

    elif temper==-1:#左边重
        for i in range(1,13):
            if i in select[0]:#左天平
                 if coin_status[i]=='ls':
                    coin_status[i]='s'
                    temp_node[1]-=1
                    temp_node[3]+=1
                 elif coin_status[i]=='lhs':
                     coin_status[i]='hs'
                     temp_node[0]-=1
                     temp_node[2]+=1
            elif i in select[1]:
                 if coin_status[i]=='hs':
                    coin_status[i]='s'
                    temp_node[2]-=1
                    temp_node[3]+=1
                 elif coin_status[i]=='lhs':
                     coin_status[i]='ls'
                     temp_node[0]-=1
                     temp_node[1]+=1
            else:
                # print(coin_status[i])
                if coin_status[i]!='s':
                    temp_node[str_key[coin_status[i]]]-=1
                    coin_status[i]='s'
                    temp_node[3]+=1
        temp_node[4]-=1
        # print(temp_node)
    else:#右边重
        for i in range(1,13):
            if i in select[0]:#左天平
                 if coin_status[i]=='hs':
                    coin_status[i]='s'
                    temp_node[2]-=1
                    temp_node[3]+=1
                 elif coin_status[i]=='lhs':
                     coin_status[i]='ls'
                     temp_node[0]-=1
                     temp_node[1]+=1
            elif i in select[1]:#右天平
                 if coin_status[i]=='ls':
                    coin_status[i]='s'
                    temp_node[1]-=1
                    temp_node[3]+=1
                 elif coin_status[i]=='lhs':
                     coin_status[i]='hs'
                     temp_node[0]-=1
                     temp_node[2]+=1
            else:
                # print(coin_status[i])
                if coin_status[i]!='s':
                    temp_node[str_key[coin_status[i]]]-=1
                    coin_status[i]='s'
                    temp_node[3]+=1
        temp_node[4]-=1
        # print(temp_node)
    return temp_node,coin_status,select
#%%
frontier=queue.PriorityQueue()
frontier.put([h(node),node,coin_status,[],[[]]])
# frontier.put([100,[0, 1, 1, 10, 0],['lhs', 's', 's', 's', 's', 's', 's', 'hs', 'ls', 's', 's', 's', 's'],[[]]])
while not frontier.empty():
    [v,node,coin_status,ch,select]=frontier.get()
    while node[4]<0 or node[0]<0 or node[1]<0 or node[2]<0 or node[3]<0:
        [v,node,coin_status,ch,select]=frontier.get()
    print(v,node,coin_status,ch,select)
    if isGoal(node):
        # print(step)
        print(coin_weight)
        print(coin_status)
        break
    else:
        # [v,node,coin_status,ch,select]=frontier.get()
        # while node[4]<0 or node[0]<0 or node[1]<0 or node[2]<0 or node[3]<0:
        #     [v,node,coin_status,ch,select]=frontier.get()
        # step.append([v,node,coin_status,ch,select])
        # print('new,',v,node,coin_status,ch,select)

        # 选取硬币的所有可能性,然后利用评估函数进行评估,并把数据储存在优先级队列中
        all_select_lhs=[[0,0]]
        for i in range(1,node[0]+1):
            for j in range(1,node[0]+1):
                if (i+j)<=node[0]:
                    all_select_lhs.append([i,j])
        all_select_ls=[[0,0]]
        for i in range(1,node[1]+1):
            for j in range(1,node[1]+1):
                if (i+j)<=node[1]:
                    all_select_ls.append([i,j])

        all_select_hs=[[0,0]]
        for i in range(1,node[2]+1):
            for j in range(1,node[2]+1):
                if (i+j)<=node[2]:
                    all_select_hs.append([i,j])
        all_select_s=[[0,0]]
        for i in range(1,node[3]+1):
            for j in range(1,node[3]+1):
                if (i+j)<=node[3]:
                    all_select_s.append([i,j])
        # print(all_select_lhs,all_select_ls,all_select_hs,all_select_s)
        left=[0,0,0,0]
        right=[0,0,0,0]
        for lhs in all_select_lhs:#穷举所有的选择
            for ls in all_select_ls:
                for hs in all_select_hs:
                    for s in all_select_s:
                        left[0]=lhs[0]
                        left[1]=ls[0]
                        left[2]=hs[0]
                        left[3]=s[0]
                        right[0]=lhs[1]
                        right[1]=ls[1]
                        right[2]=hs[1]
                        right[3]=s[1]
                        if sum(left)==sum(right) and sum(left)!=0:#选取的硬币,左右个数必须相等
                            # print('in')
                            # print(node,coin_status,left,right)
                            new_node,new_coin_status,select=AStar(node,coin_status,left,right)
                            # print('out')
                            # print(new_node,new_coin_status,select)
                            value=h(node)+h(new_node)#评估函数
                            # print("left",left,right)
                            # print('select',select)
                            # print('put',value,new_node,new_coin_status)
                            frontier.put([value,new_node,new_coin_status,[copy.deepcopy(left),copy.deepcopy(right)],select])


#%%

#%%

0是真币,1是假币比真币重
在这里插入图片描述

1是真币,0是假币比真币轻
在这里插入图片描述

其称量过程:
在这里插入图片描述

优缺点分析

在评估时,为了穷举其所有的可能,采用 了暴力法,还需要进一步优化。
可以尝试求解所有的解。

参考论文

https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CJFD&dbname=CJFD2001&filename=JSGG200121038&uniplatform=NZKPT&v=MKhLKPWPegtKfgw8IcVPKJpZpuB10ecW9v_ddgX0GppMunPqaoerCKyHQYDNpnkf

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嗯哼_Hello

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值