最大收益算法

时间:2015-03-24 03:26:55

标签: algorithm sorting

如何计算n个售票窗口的m门票所赚取的最高金额,即票价与票房的票数相等?

火车站有n个售票窗口。带窗口的(j)门票可用。票价与当时该窗口中剩余的票数相等。出售前m票的火车站可以赚到的最高金额是多少?

例如,如果我们有3个售票窗口,有3个,3个,4个门票,我们想卖5张门票。然后:

n = 3, m = 5
A[3] = {3, 3, 4}

赚取的最高金额为4 + 3 + 3 + 3 + 2 = 15

我在网上看到了这个问题,我的解决方案是首先将所有门票号码推送到maxHeap并运行for循环m次。每次我们弹出maxHeap的最高值并将其添加到所赚取的总金额中,如果该值大于1,我们将(value - 1)推送到maxHeap。

但这在某种程度上耗费时间消耗更好的解决方案?

5 个答案:

答案 0 :(得分:1)

要解决这个问题,我们需要做一个观察:

  • 要获得最大结果,我们需要获得最多m张票。

x成为窗口中剩余的最大票数,因此一个窗口i为总收入贡献的钱是

(a(i) + a(i) - 1 + ... + x + 1) = a(i)*(a(i) + 1)/2 - x*(x + 1)/2

要查找x,我们可以使用二进制搜索

int start = 0;
int end = maximum number of ticket in one window;
while(start <= end)
   int mid = (start + end)/2;
   for(each window)
      number of sell ticket += a(i) - mid;//if mid is larger than a(i), just add a zero
   if(number of sell ticket >= m)
      increase start;
   else
      decrease end;

因此,时间复杂度为O(n log m),n为窗口数,m为一个窗口中的最大票数。

答案 1 :(得分:0)

如果使用max heap,可以在O(m * logn)中完成。这是C ++代码 -

int main() {
        int *inputArray;
        int n;
        int m;
        cin >> n;
        cin >> m;
        inputArray = new int[n];
        for (int i = 0; i < n; i++) {
            cin >> inputArray[i];
        }
        cout << maximize(inputArray, n, m) << "\n";

        return 0;
    }

int maximize(int *inputArray, int n, int m){

        vector<int> v(inputArray, inputArray + n);
        int sum = 0;

        // make max heap
        make_heap(v.begin(), v.end());

        for (m = 4; m != 0; m--) {
            // get max value
            int max = v.front();

            // move max value to end and heapify
            pop_heap(v.begin(), v.end());
            // pop it out
            v.pop_back();

            sum = sum + max;

            if (max - 1) {
                // insert m-1 into vector
                v.push_back(max - 1);
                // heapify the new vector
                push_heap(v.begin(), v.end());
            }
        }

        return sum;
    }

答案 2 :(得分:0)

        package package1;
import java.util.Arrays;
import java.util.Scanner;

public class RailwayStation{
    int numOfTickets, ticketsToSell;
    int[] ticketsPerBooth;

    public RailwayStation(int numOfTickets, int ticketsToSell, int[] ticketsPerBooth)
    {
        this.numOfTickets = numOfTickets;
        this.ticketsToSell = ticketsToSell;
        this.ticketsPerBooth = ticketsPerBooth;
    }

    public int findMaxRevenue()
    {
        int[] perBooth = this.ticketsPerBooth;
        Arrays.sort(perBooth);
        int i = perBooth.length-1;
        int revenue = 0;
        while(i>=0 && ticketsToSell!=0){

            int diff = 0;
            if(i==0){

                diff = 1;
            }else{
                diff = perBooth[i] - perBooth[i-1];
            }

            while(diff!=0 && ticketsToSell!=0){

                revenue = revenue + perBooth[i];
                perBooth[i]--;
                diff--;
                ticketsToSell--;

            }
            if(ticketsToSell!=0 && i==0){
                i = perBooth.length-1;
            }else{
                i--;
            }


        }
        return revenue;
    }

    public static void main(String[] args) 
    {
        Scanner sc = new Scanner(System.in);
        int numOfBooths = sc.nextInt();
        int ticketsToSell = sc.nextInt();
        int perBooth[] = new int[numOfBooths];
        for(int i = 0; i < numOfBooths; i++)
        {
            perBooth[i] = sc.nextInt();
        }
        RailwayStation rt = new RailwayStation(numOfBooths, ticketsToSell, perBooth);
        System.out.println("Max Revenue = " + rt.findMaxRevenue());
    }
}

答案 3 :(得分:0)

“”“修改后的阶乘,直到该轮的索引限制”“

def modified_fact(限制,数字):     sum_fact = 0     对于范围内的i(数字 - 限制+ 1,数字+ 1):         sum_fact + = i     return sum_fact

''” 我已经计算了我需要做多少回合才能减少。在最后一次迭代中,我需要什么索引 迭代。

'''

def maximum_earning_algorithm(n,windows):     “”“

:param windows:
:param n:
:rtype: int
"""
money = 0
final_round_limit_index = n % len(windows)
rounds = n / (len(windows))
print final_round_limit_index, rounds
for i in range(len(windows)):
    if i < final_round_limit_index:
        money += modified_fact(rounds + 1, windows[i])
    else:
        money += modified_fact(rounds, windows[i])
return money

如果名称 =='主要':     窗口= [5,4,3]     print maximum_earning_algorithm(3,window)

答案 4 :(得分:0)

方法1)
作为@ n.m.指出MaxHeap解决方案的小优化:

您无需逐个删除票证。如果您有一个顶部窗口,您需要知道它有多少票,以及下一张票有多少票。然后,您可以删除差异并在一次操作中计算总价。 稍作修改,如果您有多个具有相同最大票数的窗口,则可以执行相同的操作。

方法2)使用排序数组:

将窗口加载到数组中。对数组进行排序。向后遍历数组并执行:存储该数字(当前),将其添加到聚合器,转到下一个值。如果它是相同的(当前),则将其添加到聚合器,从中减去1,继续。如果不同,请返回到数组的末尾并重新开始。做N次(内部循环,而不是外部循环)。

方法3)使用计数数组(线性时间复杂度):

  1. 创建索引为no的数组。门票和价值观没有。有许多门票的摊位。因此,{0-> 0,1-> 1,2-> 0,3-> 2}意味着1档有1张票,2档有3张票

  2. 从数组的最高索引(count -1)开始,将该索引添加到聚合器(A),使A = 3,然后将该索引(3)减少1比1,并增加索引低于(= 2)1到1 数组是{0,1,1,1},A = 3。重复。 A = 6,数组为{0,1,2,0}。最后一个索引为零,因此将指针移动到索引2 重复,所以A = 8,数组= {0,2,1,0}。重复。 A = 10,数组为{0,5,0,0} 你已经完成了t次(销售门票数量)停止。

  3. 以下是此方法的实施:

    int[] stalls = new int[] { 3,1,3 }; // 2 stalls have 3 tickets each and 1 stall have 1 ticket
            int t = 4;
    
            Arrays.sort(stalls);
    
            int tickets = stalls[stalls.length - 1];
            int[] dp = new int[tickets + 1];
    
            for (int i = 0; i < stalls.length; i++) {
                dp[stalls[i]]++;
            }
    
            int total = 0;
            int i = dp.length - 1;
    
            while (t > 0) {
                if (dp[i] > 0) {
                    total += i;
                    t--;
                    dp[i]--;
                    dp[i - 1]++;
                } else {
                    i--;
                }
            }
    
            System.out.println(total);