随机试探
- 0/1背包问题
- 随机种子
- 换一台电脑试试
- 随机试探
- 代码
- 测试
- 更改限定次数和试探次数测试
- 贪心算法
- 打印
0/1背包问题
![]() |
---|
里面提到了穷举法,贪心算法,分支界限法,还列出了动态规划的思路。
随机种子
让生成的随机数每次都一样。随机种子一直有用吗?重新打开应用,电脑关了再打开,生成的随机数还是一样吗?
import random
def seedtest(S=0):
random.seed(S)
return [random.random() for _ in range(10)]
'''
[0.8444218515250481, 0.7579544029403025, 0.420571580830845, 0.25891675029296335,
0.5112747213686085, 0.4049341374504143, 0.7837985890347726, 0.30331272607892745,
0.4765969541523558, 0.5833820394550312]
'''
#重启电脑还是这样的输出。
Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
>>>
================== RESTART: C:\Program Files\Python38\seed.py ==================
>>> seedtest()
[0.8444218515250481, 0.7579544029403025, 0.420571580830845, 0.25891675029296335, 0.5112747213686085, 0.4049341374504143, 0.7837985890347726, 0.30331272607892745, 0.4765969541523558, 0.5833820394550312]
>>>
我这里测试是这样的。
换一台电脑试试
也是一样的结果。
Python 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
======================= RESTART: E:/老公/python/seedtest.py ======================
seedtest()
[0.8444218515250481, 0.7579544029403025, 0.420571580830845, 0.25891675029296335, 0.5112747213686085, 0.4049341374504143, 0.7837985890347726, 0.30331272607892745, 0.4765969541523558, 0.5833820394550312]
随机试探
重量和价值如下:
weights = [87,66,70,25,33,24,89,63,23,54]
values = [96,55,21,58,41,81,8,99,59,62]
限定重量:250
试探次数:200
测试有没有最优解。
代码
import random
weights = [87,66,70,25,33,24,89,63,23,54]
values = [96,55,21,58,41,81,8,99,59,62]
N = len(weights)
SEED = 32767 #再打开还有用吗,关机?
R = 10
def solvekp(p,weightlimit,nlimit,N):
maxvalue = 0
mweight = 0
bestp = [0 for i in range(N)]
for i in range(nlimit):
rsetp(p,N)
weight = calcw(p,N)
if weight <= weightlimit:
value = calval(p,N)
else:
value = 0
if value >maxvalue:
maxvalue = value
mweight = weight
for j in range(N):
bestp[j] = p[j]
print(maxvalue," ",mweight)
print(bestp)
def calcw(p,N):
w = 0
for i in range(N):
w += weights[i] * p[i]
return w
def calval(p,N):
v = 0
for i in range(N):
v += values[i]*p[i]
return v
def rsetp(p,N):
for i in range(N):
p[i] = int(random.random()*2)
p = [0 for i in range(N)]
weightlimit = int(input("请输入限定重量:"))
nlimit = int(input("请输入试探次数:"))
random.seed(SEED)
for i in range(R):
solvekp(p,weightlimit,nlimit,N)
测试
=================== RESTART: C:\Program Files\Python38\rkp.py ==================
请输入限定重量:250
请输入试探次数:200
400 222
[0, 0, 0, 1, 1, 1, 0, 1, 1, 1]
338 168
[0, 0, 0, 1, 1, 1, 0, 1, 1, 0]
359 238
[0, 0, 1, 1, 1, 1, 0, 1, 1, 0]
376 230
[1, 0, 0, 0, 1, 1, 0, 1, 1, 0]
356 213
[1, 0, 0, 1, 0, 1, 0, 0, 1, 1]
393 222
[1, 0, 0, 1, 0, 1, 0, 1, 1, 0]
397 246
[1, 0, 0, 1, 1, 1, 0, 0, 1, 1]
393 222
[1, 0, 0, 1, 0, 1, 0, 1, 1, 0]
393 222
[1, 0, 0, 1, 0, 1, 0, 1, 1, 0]
397 246
[1, 0, 0, 1, 1, 1, 0, 0, 1, 1]
>>>
从测试结果看,有两百次,有十次是没有超重的。第一个最大价值400就是最优解。
更改限定次数和试探次数测试
=================== RESTART: C:\Program Files\Python38\rkp.py ==================
请输入限定重量:300
请输入试探次数:20
396 253
[1, 0, 0, 1, 0, 1, 0, 1, 0, 1]
371 293
[1, 1, 0, 0, 0, 0, 0, 1, 1, 1]
431 296
[1, 1, 0, 0, 1, 1, 0, 1, 1, 0]
331 235
[1, 1, 0, 1, 1, 1, 0, 0, 0, 0]
397 251
[1, 0, 0, 0, 0, 1, 0, 1, 1, 1]
434 255
[1, 0, 0, 1, 1, 1, 0, 1, 1, 0]
408 297
[1, 1, 0, 1, 1, 0, 0, 1, 1, 0]
362 269
[0, 0, 1, 1, 1, 1, 0, 1, 0, 1]
360 291
[1, 0, 1, 0, 1, 1, 0, 0, 1, 1]
319 198
[0, 0, 0, 1, 1, 0, 0, 1, 1, 1]
>>>
=================== RESTART: C:\Program Files\Python38\rkp.py ==================
请输入限定重量:200
请输入试探次数:10
193 184
[0, 1, 1, 1, 0, 0, 0, 0, 1, 0]
247 194
[0, 0, 0, 1, 1, 1, 1, 0, 1, 0]
213 152
[0, 1, 0, 0, 0, 0, 0, 1, 1, 0]
235 148
[0, 1, 0, 1, 1, 1, 0, 0, 0, 0]
157 160
[0, 1, 1, 0, 0, 1, 0, 0, 0, 0]
278 165
[0, 0, 0, 1, 0, 0, 0, 1, 1, 1]
198 193
[0, 1, 1, 0, 1, 1, 0, 0, 0, 0]
154 112
[1, 0, 0, 1, 0, 0, 0, 0, 0, 0]
0 0
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0 0
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>>
贪心算法
排序后只找一遍,不是比较所有解。
def dictsum(list, keyname):#计算总价值、总重量
num = 0
for item in list:
num += item[keyname]
return num
class G():
'''
每个都做第一次放试探了。
'''
def __init__(self, d, m):
self.m = m
#self.dl=sorted(self.rd(d),key=lambda x:x.__getitem__("a"),reverse=True)
self.dl = sorted(self.rd(d), key=lambda x:x["a"], reverse=True) #按单位价低到高排序
print(self.dl)
self.sl = [] #选择的解
def rd(self, d):
"""
read data
w for weight
"""
for i in d:
v = i["p"] / i["w"]
i.setdefault("a", v)
return d
def pick(self):
tl = []
tw = self.m
for j in range(len(self.dl)):#贪心算法,排序后只找一次,不是比较所有解
if self.dl[j]["w"] <= tw:#顺序加满一个解
tl.append(self.dl[j])
tw -= self.dl[j]["w"]
if [] != tl and dictsum(tl, "p") > dictsum(self.sl, "p"):#剪枝
self.sl = tl
return tl, dictsum(tl,"w"), dictsum(tl,"p")
d = [{"w":87,"p":96}, {"w":66,"p":55}, {"w":70,"p":21}, {"w":25,"p":58},
{"w":33,"p":41}, {"w":24,"p":81}, {"w":89,"p":8}, {"w":63,"p":99},
{"w":23,"p":59}, {"w":54,"p":62},]
m = 250
s, sw, sp = G(d, m).pick()
r = json.dumps([{"select":s, "weight":sw, "price":sp}])
打印
计算的单价
[{'w': 24, 'p': 81, 'a': 3.375}, {'w': 23, 'p': 59, 'a': 2.5652173913043477}, {'w': 25, 'p': 58, 'a': 2.32}, {'w': 63, 'p': 99, 'a': 1.5714285714285714}, {'w': 33, 'p': 41, 'a': 1.2424242424242424}, {'w': 54, 'p': 62, 'a': 1.1481481481481481}, {'w': 87, 'p': 96, 'a': 1.103448275862069}, {'w': 66, 'p': 55, 'a': 0.8333333333333334}, {'w': 70, 'p': 21, 'a': 0.3}, {'w': 89, 'p': 8, 'a': 0.0898876404494382}]
选择的物品,从单价高的往下选。
[{"select": [{"w": 24, "p": 81, "a": 3.375}, {"w": 23, "p": 59, "a": 2.5652173913043477}, {"w": 25, "p": 58, "a": 2.32}, {"w": 63, "p": 99, "a": 1.5714285714285714}, {"w": 33, "p": 41, "a": 1.2424242424242424}, {"w": 54, "p": 62, "a": 1.1481481481481481}],
结果
"weight": 222, "price": 400}]
跟随机算法一样,设置250总重量时,选择的是222重量,400价值。