Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 一种高效地用组替换数组元素的算法_Python_Algorithm - Fatal编程技术网

Python 一种高效地用组替换数组元素的算法

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个项目的最低成本 在该示例中,最有利的做法是采用两个组并分别购买

有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个项目的最低成本

在该示例中,最有利的做法是采用两个组并分别购买编号为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)