试题 历届真题 补给【第十一届】【决赛】【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上,也用于构造物品状态
^按位异或,和 |或 相反,用于回溯状态。
通过情况: