Python 一种高效地用组替换数组元素的算法
有N个元素,每个元素都有自己的成本。有M组。每个组包括数组中元素的多个索引,并且有自己的成本 例如输入Python 一种高效地用组替换数组元素的算法,python,algorithm,Python,Algorithm,有N个元素,每个元素都有自己的成本。有M组。每个组包括数组中元素的多个索引,并且有自己的成本 例如输入 6 100 5 200 5 300 5 400 5 500 5 600 3 2 4 6 100 200 300 700 3 5 300 400 500 第一个数字N是元素的数量。接下来的N行包含特定项目的索引和成本。然后是数字M(组数)。之后是2*M线。这些行包含组中元素的数量、组本身的成本以及元素的索引 我想找到可以购买所有N个项目的最低成本 在该示例中,最有利的做法是采用两个组并分别购买
6
100 5
200 5
300 5
400 5
500 5
600 3
2
4 6
100 200 300 700
3 5
300 400 500
第一个数字N是元素的数量。接下来的N行包含特定项目的索引和成本。然后是数字M(组数)。之后是2*M线。这些行包含组中元素的数量、组本身的成本以及元素的索引
我想找到可以购买所有N个项目的最低成本
在该示例中,最有利的做法是采用两个组并分别购买编号为600的元素。答案是14。(6+5+3)
这是我的解决办法
from queue import PriorityQueue
N = int(input())
dct = {}
groups = PriorityQueue()
for i in range(N):
a,c = [int(j) for j in input().split()]
dct[a] = c
M = int(input())
for i in range(M):
k,c = [int(j) for j in input().split()]
s = 0
tmp = []
for j in input().split():
j_=int(j)
if j_ in dct:
s+=dct[j_]
tmp.append(j_)
d = c-s
if d<0:
groups.put([d, c, tmp])
s = 0
while not groups.empty():
#print(dct)
#for i in groups.queue:
# print(i)
g = groups.get()
if g[0]>0:
break
#print('G',g)
#print('-------')
for i in g[2]:
if i in dct:
del(dct[i])
s += g[1]
groups_ = PriorityQueue()
for i in range(len(groups.queue)):
g_ = groups.get()
s_ = 0
tmp_ = []
for i in g_[2]:
if i in dct:
s_+=dct[i]
tmp_.append(i)
d = g_[1]-s_
groups_.put([d, g_[1], tmp_])
groups = groups_
for i in dct:
s+=dct[i]
print(s)
我也尝试过暴力搜索,但这样的解决方案太慢了
from itertools import combinations
N = int(input())
dct = {}
s = 0
for i in range(N):
a,c = [int(j) for j in input().split()]
dct[a] = c
s += c
m = s
M = int(input())
groups = []
for i in range(M):
k,c = [int(j) for j in input().split()]
s = 0
tmp = []
for j in input().split():
j_=int(j)
if j_ in dct:
s+=dct[j_]
tmp.append(j_)
groups.append( [c, tmp] )
for u in range(1,M+1):
for i in list(combinations(groups, u)):
s = 0
tmp = dct.copy()
for j in i:
s += j[0]
for t in j[1]:
if t in tmp:
del(tmp[t])
for j in tmp:
s += tmp[j]
#print(i,s)
if s < m:
m = s
print(m)
来自itertools导入组合的
N=int(输入())
dct={}
s=0
对于范围(N)中的i:
a、 c=[input().split()中j的int(j)]
dct[a]=c
s+=c
m=s
M=int(输入())
组=[]
对于范围内的i(M):
k、 c=[input().split()中j的int(j)]
s=0
tmp=[]
对于输入()中的j.split():
j_u=int(j)
如果j_u在dct中:
s+=dct[j_2;]
tmp.append(j_)
groups.append([c,tmp])
对于范围(1,M+1)内的u:
对于列表中的i(组合(组,u)):
s=0
tmp=dct.copy()
对于i中的j:
s+=j[0]
对于j[1]中的t:
如果tmp中有t:
del(tmp[t])
对于tmp中的j:
s+=tmp[j]
#打印(i,s)
如果s
我认为这个问题是在动态规划的帮助下解决的。也许这是典型背包问题的一些变体。告诉我哪种算法更适合使用。所谓的(NP难)似乎是你问题的特例。因此,恐怕没有有效的算法来解决它。正如前面所说的,这是一个没有“有效”算法的难题 您可以将其视为一个图问题,图中的节点都是组的可能组合(每个元素本身也是一个组)。当存在一组g时,两个节点u和v通过一条有向边连接,使得u和g中的键的并集对应于v中的键集 然后在此图中执行Dijkstra搜索,从表示完全没有选择组的状态(成本为0,没有键)的节点开始。此搜索将最小化成本,并且您可以使用额外的优化,即g组在同一路径中不会被考虑两次。一旦访问了覆盖所有密钥的状态(节点),就可以退出该算法——典型的Dijkstra算法——因为这表示覆盖所有密钥的最小成本 这样的算法仍然非常昂贵,因为每次向路径添加一条边时,都必须计算关键点的并集。而且,。。。需要相当多的内存来保持堆中的所有状态 下面是一个可能的实现:
从集合导入namedtuple
进口heapq
#一些命名的元组类型,以使代码更具可读性
组=名称组(“组”,“成本numtodo键”)
Node=namedtuple(“Node”,“cost numtodo keys nextgroupid”)
def collectinput():
inputNumbers=lambda:[int(j)表示input()中的j。split()]
组=[]
键=[]
N、 =输入编号()
对于范围(N)中的i:
密钥,成本=输入编号()
key.append(key)
把这些原子键也看成是群(有一个键)
#这个元组的中间元素可能看起来很肤浅,但它改进了排序
追加(组(成本,N-1,[键])
关键点=设置(关键点)
M、 =输入编号()
对于范围内的i(M):
成本=输入编号()[-1]
groupkeys=[key for key in inputNumbers()如果是key in keys]
groups.append(组(cost,N-len(groupkey),groupkey))
返回键、组
def solve(键、组):
N=长度(键)
groups.sort()#按成本排序(如果相等),按剩余键数排序
#图形搜索的起始节点
heap=[节点(0,N,[],0)]
而len(堆):
node=heapq.heappop(堆)
如果node.numtodo==0:
返回节点成本
对于范围内的i(node.nextgroupid,len(groups)):
组=组[i]
unionkeys=列表(设置(node.keys+group.keys))
如果len(unionkeys)>len(node.keys):
heapq.heappush(堆,节点(Node.cost+group.cost,N-len(unionkey),unionkey,i+1))
#主要
键,组=collectinput()
成本=解决(关键点、组)
打印(“解决方案:{}”。格式(成本))
您发布的第二个问题的结果是160。我想说动态规划有很好的工作机会,但是可能必须对数值
N
和M
进行限制才能有效解决问题。我使用的是这个特殊的算法。你可以看到我的代码。但是为什么它对我所指出的测试做出了错误的决定呢?这样的解决方案并不比暴力搜索好多少。我认为这个问题是通过贪婪算法解决的。
from itertools import combinations
N = int(input())
dct = {}
s = 0
for i in range(N):
a,c = [int(j) for j in input().split()]
dct[a] = c
s += c
m = s
M = int(input())
groups = []
for i in range(M):
k,c = [int(j) for j in input().split()]
s = 0
tmp = []
for j in input().split():
j_=int(j)
if j_ in dct:
s+=dct[j_]
tmp.append(j_)
groups.append( [c, tmp] )
for u in range(1,M+1):
for i in list(combinations(groups, u)):
s = 0
tmp = dct.copy()
for j in i:
s += j[0]
for t in j[1]:
if t in tmp:
del(tmp[t])
for j in tmp:
s += tmp[j]
#print(i,s)
if s < m:
m = s
print(m)