状压DP/蓝桥杯2019A组真题

状压dp:二进制状态+位运算

状态是二进制表示,十进制数是这个状态的名字。在本题中,状态state是m位二进制数,m是口味编号,1代表吃了,0代表没吃到,101100表示吃了第三,四,六个口味的糖(因为二进制数是低位在右高位在左,编号从右往左)dp[state]表示到达这个状态买最少几包糖。初始化无穷大,因为更新dp的值是找小的更新,dp[0]=0表示一个口味都不吃需要买0包。

wd=wd|(1<<(candy-1)) 味道相与把这一包糖的味道用二进制表示,与的特点就是只有0|0=0其余都为一,也不用考虑重复了,比如口味112就是011,123就是111,candy-1是因为二进制最低位是2**0,而糖果口味编号从1开始。
状态转移方程:dp[state|wd]=min(dp[state|wd],dp[state]+1),state|wd就是在state的基础上吃了一包wd的糖,比如说万一一包糖的味道都在state里面,以前都吃过了,那么dp[state|wd]=dp[state]<dp[state]+1,保持值不变,万一有没吃过的,dp[state|wd]就是比较当前值和上一个状态买这包糖,哪个买的少,也就是说不同的路到这个状态找一个最小值。

1<<m表示1后面带m个0,表示2**m,而2**m-1才表示m个1,就是m个口味都吃过了。

n,m,k=map(int,input().split())#m种口味,n包糖,一包k个
dp=[float('inf') for _ in range(1<<m)]#2**m个数表示1到m个口味被尝过的状态
dp[0]=0
candies=[]
for _ in range(n):
    candi=list(map(int,input().split()))
    candies.append(candi)
for packet in candies:
    wd=0#糖果口味1,转化为1(1),糖果口味为2,转化为10(2),3变成100(4),1左移candy-1位
    for candy in packet:
     wd=wd|(1<<(candy-1))  
     for state in range(1<<m):
         dp[state|wd]=min(dp[state|wd],dp[state]+1)
    
all_flavors = (1 << m) - 1 
if dp[all_flavors] != float('inf'):
    print(dp[all_flavors])
else:
    print('-1')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值