状压dp(python)蓝桥杯补给

试题 历届真题 补给【第十一届】【决赛】【B组】

提交此题   评测记录  

资源限制

内存限制:256.0MB   C/C++时间限制:1.0s   Java时间限制:3.0s   Python时间限制:5.0s

旅行商的变种题,区别在于经历过的地点还可以过去,所以动态转移方程为:

dp[i][state] 是指 从i出发,经历state 的状态再回到0 的最短距离

dp[i][state]=min(dp[j][sub]+diji(i,j)) if state&(1<<j) !=0 也就是说 中间中转站 得是已经经过的地方

其中,sub 是 (1<<j)^state ,也就是上层遍历时,其他地点都去了唯独没去 j 的情况

diji(i,j) 是用迪基求i到j的最短距离。

Python真的离谱, 跑啥都跑不过去,慢死 ,只跑了50%

喜讯:经过2/5坤年的练习,本次更新的demo可以跑到70%。

什么?python的优先队列竟然是小顶堆!这题能跑过去纯是因为这题的数据水,迪杰斯特拉根本就没意义!直到我做了交通信号那个题才知道,我tmd调了半天,硬是没看出来,差点给你们写错了!现在已经改过来了

code:

import copy
import math
from queue import PriorityQueue
from collections import deque
n,d=map(int,input().split())
mp=[[float("inf") for  _ in range(n+1)] for _ in range(n+1)]
mid=[0]
def fun(x1,y1,x2,y2):
    return math.sqrt((x2-x1)**2+(y2-y1)**2)
#预处理合法的初始图
for _ in range(n):
    x1,y1=map(int,input().split())
    for i in range(1,len(mid)):
        dij=fun(x1,y1,mid[i][0],mid[i][1])
        if (dij<=d):
            mp[_+1][i]=min(mp[_+1][i],dij)
            mp[i][_ + 1]=min(dij,mp[i][_ + 1])
    mid.append([x1,y1])
#diji求全图最短路  利用大根堆,程序嘎嘎快
del mid
#q=[[]for i in range(n+1)]

class pair():
    def __init__(self,v,w):
        self.v=v
        self.w=w
    def __lt__(self, other):
        return self.w<other.w
def dji(x):

    pque=PriorityQueue()
    dis=[float("inf") for i in range(n+1)]
    vis=[True for i in range(n+1)]
    pque.put(pair(x,0))
    dis[x]=0
    while pque.qsize():

        mid=pque.get()
        v=mid.v

        if (vis[v]==False):continue
        vis[v]=False
        for i in range(1,n+1):
            if (dis[i]>dis[v]+mp[v][i]):
                dis[i] = dis[v] + mp[v][i]
                pque.put(pair(i,dis[i]))

    mp[x]=copy.deepcopy(dis)
for i in range(1,n+1):
    dji(i)

dp=[[float("inf") for i in range((1<<n))]for i in range(n)]
for i in range(n):
    dp[i][0]=mp[i+1][1]

for i in range(1,1<<n):
    for j in range(n):
        #if (1<<j)&i ==0: continue
        for k in range(n):
            if (1<<k)&i !=0 :
                mid=(1<<k)^i
                dp[j][i]=min(dp[j][i],dp[k][mid]+mp[k+1][j+1])
print("{:.2f}".format(dp[0][-1]))



"""
4 10
1 1
5 5
1 5
5 1
"""

总结下状压dp的常见操作吧

&与,用于判断该状态是否被包括在state中

|或,用于将状态加到state上,也用于构造物品状态

^按位异或,和 |或 相反,用于回溯状态。

通过情况:

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值