贪心算法按顺序查找潜在的加权活动?

时间:2014-01-02 05:04:33

标签: algorithm optimization

例如,假设有一系列活动{a,b,c,d,e,f,g}

a & b are worth 9 points each. 
c is worth 8 points. 
d & e are worth 6 points each. 
f is worth 5 points.
g is worth 4 points.

活动列表已按降序排序。

我想找到三个活动的最高点组合(让我们称这个组合X)满足某些要求(例如F(X)=真)。

F(X)只接受三种活动的组合,不能修改。

如何在不先计算所有可能的组合的情况下生成X?
如何在降低总分数时迭代所有可能的组合?

我希望能够找到最高点组合,进行测试。如果失败,则生成第二高点组合等。

示例列表只是几个项目。但是,实际列表可能会非常大,生成所有组合是不切实际的。

我该怎么做?

5 个答案:

答案 0 :(得分:0)

我认为没有一个很好的解决方案来满足您的要求。这是我能想到的最好(也是最差)的解决方案:生成所有组合,将它们放入向量然后排序!复杂性为O(n^3 log(n^3))。我认为只有很少的改进可以通过假设在同一位置没有多次具有相同值的点来生成已经生成的组合。

在c ++中的实现:

#include <stdio.h>
#include <algorithm>
#include <vector>
using namespace std;

struct Combin {
    int a, b, c, sum;
};

bool comp(Combin a, Combin b) {
    return a.sum>b.sum;
}

int main() {
    vector<int> act;
    int n;
    while(scanf("%d", &n)==1 && n) {
        act.push_back(n);
    }

    vector<Combin>combs;

    for (int i=0; i<act.size(); i++) {
        if (i>0 && act[i-1]==act[i]) continue;
        for (int j=i+1; j<act.size(); j++) {
            if (j>i+1 && act[j-1]==act[j]) continue;
            for (int k=j+1; k<act.size(); k++) {
                if (k>j+1 && act[k-1]==act[k]) continue;
                    Combin comb;
                    comb.a=i; comb.b=j; comb.c=k;
                    comb.sum = act[i]+act[j]+act[k];
                    combs.push_back(comb);
            }
        }
    }

    sort(combs.begin(), combs.end(), comp);

    for (int i=0; i<combs.size(); i++) {
        printf("(%d,%d,%d)=%d\n", act[combs[i].a], act[combs[i].b], act[combs[i].c], combs[i].sum);
    }

    return 0;
}

答案 1 :(得分:0)

以下是生成三个有序组合的方法: -

    for(int i=0;i<Set.size();i++) {

       for(int j=i+1;j<Set.size();j++) {

           for(int k=j+1;k<Set.size();k++) {

                   if(F(Set[i],Set[j],Set[k])) {
                       // your code to find max
                   }  
           }
       }

}

答案 2 :(得分:0)

以下想法只能解决问题的简单版本,但也许可以扩展到更强大的解决方案。

设[a(1).. a(N)]为输入数组。 我在这里建议的是一种枚举顶部N ^(1/3)三元组的方法,在完全枚举中的C(N,3)~N ^ 3个三元组中。我知道这是适度的,但它保证 O(N)时间和空间

  1. s = a(1)+ a(2)+ a(N ^(1/3))
  2. T = [a(1),a(2),..,a(N ^(1/3))]中的所有三元组(需要O(N)时间和空间)
  3. 按降序三重和顺序排序T(时间复杂度:O(N ^(1/3)* log N)= O(N))
  4. 迭代T并返回每个三元组r,而sum(r)&gt; = s
  5. <强>解释

    在(1)中,我们计算三元组可能的最高分数,该三元组不仅涉及来自T = [a(1)... a(N ^(1/3))]的项目。换句话说,T已经包含所有得分的三元组&gt;秒。因此,我们在T中生成所有三元组,对它们进行排序,并仅返回我们确定的那些(即得分> = s的那些)。将返回多少这样的三胞胎?好吧,这取决于数组值,但我们可以保证至少N ^(1/3) - 2个三元组,因为{{1}的所有三元组[a(1)+ a(2)+ a(i)]总和&gt; = s。实际上,“好”三元组的数量可能要高得多,但这又取决于阵列号分布。

答案 3 :(得分:0)

我记得Pythons组合生成器倾向于保持其输入的LHS到RHS从最小到最大,并首先输出LHS术语。

如果您使用Pythons方法生成组合,其docs个状态如下:

def combinations(iterable, r):
    # combinations('ABCD', 2) --> AB AC AD BC BD CD
    # combinations(range(4), 3) --> 012 013 023 123
    pool = tuple(iterable)
    n = len(pool)
    if r > n:
        return
    indices = range(r)
    yield tuple(pool[i] for i in indices)
    while True:
        for i in reversed(range(r)):
            if indices[i] != i + n - r:
                break
        else:
            return
        indices[i] += 1
        for j in range(i+1, r):
            indices[j] = indices[j-1] + 1
        yield tuple(pool[i] for i in indices)

然后你可以按权重递减顺序给你的项目功能,以减少重量顺序生成项目:

for x in combinations('abcdef', 3): 
    print(x)

('a', 'b', 'c')
('a', 'b', 'd')
('a', 'b', 'e')
('a', 'b', 'f')
('a', 'c', 'd')
('a', 'c', 'e')
('a', 'c', 'f')
('a', 'd', 'e')
('a', 'd', 'f')
('a', 'e', 'f')
('b', 'c', 'd')
('b', 'c', 'e')
('b', 'c', 'f')
('b', 'd', 'e')
('b', 'd', 'f')
('b', 'e', 'f')
('c', 'd', 'e')
('c', 'd', 'f')
('c', 'e', 'f')
('d', 'e', 'f')

注意:正如Essam在评论中指出的,组合(数据,3)相当于comb3(数据),其中:

def comb3(data):
    lendata = len(data)
    for i in range(lendata):
        for j in range(i+1, lendata):
            for k in range(j+1, lendata):
                yield (data[i], data[j], data[k])

答案 4 :(得分:0)

我只是按照特定顺序使用生成的组合的另一个答案并没有给出完全排序的答案。实际上他们将在35场比赛中有6场比赛,其中下一场比赛的总数上升而不是下降。

如果我们使用这些组合但是将它们放在一个固定的最大大小的堆中,那么我们可以交换最大堆大小以获得排序的准确性:

from itertools import combinations
from heapq import heappush, heappop, heappushpop

BESTOFLAST = 10     # max heap size

item2points = dict(a=9, b=9, c=8, d=6, e=6, f=5, g=4)

def partially_ordered_triples(item2points, BESTOFLAST=BESTOFLAST):
    ordereditems = sorted(item2points.keys(), 
                        key=lambda item: item2points[item],
                        reverse=True)
    #print(ordereditems)    # ['a', 'b', 'c', 'e', 'd', 'f', 'g']

    triples = combinations(ordereditems, 3)

    heap = []   # Empty heap

    # Preload heap
    for i in range(BESTOFLAST):
        triple = triples.next()
        total = sum(item2points[item] for item in triple)
        heappush(heap, (-total, triple))    # minheap so -total

    # load/remove from heap in partially sorted order    
    for triple in triples:
        total = sum(item2points[item] for item in triple)
        thistotal, thistriple = heappushpop(heap, (-total, triple))
        yield thistriple, -thistotal

    # drain rest of heap
    while heap:
        thistotal, thistriple = heappop(heap)
        yield thistriple, -thistotal

if __name__ == '__main__':
    for heapsize in range(BESTOFLAST + 1):
        print('Using a heap of size: %i and skipping:' % heapsize)
        length = skipped = 0
        previoustotal = sum(item2points.values())   # Starting high value
        for triple, newtotal in partially_ordered_triples(item2points, heapsize):
            if newtotal > previoustotal: skipped += 1
            length += 1
            previoustotal = newtotal

        print(" of %i triples, %i were skipped to keep the total count decreasing" % (length, skipped))

如果堆的大小足够大,那么将不会偏离所需的顺序。如果太小,则偏差的数量会增加:

输出:

Using a heap of size: 0 and skipping:
 of 35 triples, 6 were skipped to keep the total count decreasing
Using a heap of size: 1 and skipping:
 of 35 triples, 4 were skipped to keep the total count decreasing
Using a heap of size: 2 and skipping:
 of 35 triples, 4 were skipped to keep the total count decreasing
Using a heap of size: 3 and skipping:
 of 35 triples, 3 were skipped to keep the total count decreasing
Using a heap of size: 4 and skipping:
 of 35 triples, 2 were skipped to keep the total count decreasing
Using a heap of size: 5 and skipping:
 of 35 triples, 2 were skipped to keep the total count decreasing
Using a heap of size: 6 and skipping:
 of 35 triples, 1 were skipped to keep the total count decreasing
Using a heap of size: 7 and skipping:
 of 35 triples, 1 were skipped to keep the total count decreasing
Using a heap of size: 8 and skipping:
 of 35 triples, 1 were skipped to keep the total count decreasing
Using a heap of size: 9 and skipping:
 of 35 triples, 0 were skipped to keep the total count decreasing
Using a heap of size: 10 and skipping:
 of 35 triples, 0 were skipped to keep the total count decreasing