📌  相关文章
📜  处理 m 个任务的最小成本,其中转换成本

📅  最后修改于: 2021-10-26 06:32:47             🧑  作者: Mango

有n个处理器核心。每个核心一次可以处理一个任务。不同的内核可以同时处理不同的任务,而不会影响其他内核。假设队列中有 m 个任务,处理器必须处理这 m 个任务。同样,这 m 个任务并非都是类似的类型。任务类型用数字表示。因此,m 个任务表示为 m 个连续的数字,相同的数字表示相同类型的任务,例如 1 表示类型 1 的任务,2 表示类型 2 的任务等等。

最初,所有内核都是免费的。在内核中启动一种类型的任务需要一个单位的成本,该内核当前未在该内核中运行。在每个核心上开始启动任务时将收取一个单位成本。例如,一个核心正在运行类型 3 任务,如果我们在该核心中再次分配类型 3 任务,则此分配的成本将为零。但是,如果我们分配类型 2 任务,则此分配的成本将为一个单位。一个核心一直在处理一个任务,直到下一个任务被分配给那个核心。

例子 :

Input : n = 3, m = 6, arr = {1, 2, 1, 3, 4, 1}
Output : 4

Input : n = 2, m = 6, arr = {1, 2, 1, 3, 2, 1}
Output : 4
Explanation : 

Input : n = 3, m = 31, 
arr = {7, 11, 17, 10, 7, 10, 2, 9, 2, 18, 8, 10, 20, 10, 3, 20,
       17, 17, 17, 1, 15, 10, 8, 3, 3, 18, 13, 2, 10, 10, 11}
Output : 18

说明(对于第一个示例 I/O):这里的内核总数为 3。让 A、B 和 C。首先在任何内核中分配类型 1 的任务 -> 成本 1 个单位。状态:A – 1,B – 无,C – 无。在其余 2 个核心中的任何一个中分配类型 2 的任务 -> 成本 1 个单位。状态:A – 1、B – 2、C – 无。然后在该核心中分配类型 1 的任务,其中类型 1 的任务正在进行 – > 成本 0 单位。状态:A – 1、B – 2、C – 无。
在免费核心中分配类型 3 的任务 -> 成本 1 单位。状态:A – 1、B – 2、C – 3。

现在,所有内核都在运行一个任务。所以我们必须在这些核心之一中分配类型 4 的任务。让我们将它加载到核心 B 中,之前类型 2 的任务正在进行 -> 成本 1 单位。

状态:A – 1, B – 4, C – 3. 现在,在核心 A 中加载类型 1 任务,其中类型 1 任务正在运行 -> 成本 0 单位。状态:A – 1,B – 4,C – 3。因此,总成本 = 1 + 1 + 0 + 1 + 1 + 0 = 4 u
单位。

解释 2(对于第二个样本 I/O):内核总数为 2。让 A 和 B。在任何内核中的第一个类型 1 的处理任务 -> 成本 1 个单位。状态:A – 1,B – 无。在其余 2 个核心中的任何一个中处理类型 2 的任务 -> 成本 1 个单位。状态:A – 1,B – 2。然后在该核心中处理类型 1 的任务,其中类型 1 的任务正在进行 -> 成本 0 单位。状态:A – 1,B – 2。现在,让我们将类型 3 的任务分配给核心 A -> 成本 1 单位。状态:A – 3,B – 2。现在,在核心 B 中分配类型 2 任务,其中已经进行了类型 2 任务 -> 成本 0 单位。状态:A – 3,B – 2。因此,总成本 = 1 + 1 + 0 + 1 + 1 = 4 个单位。最后在任何核心中分配类型 1 任务(例如 A)-> 成本 1 单位。状态:A – 1,B – 2。因此,总成本 = 1 + 1 + 0 + 1 + 0 + 1 = 4 个单位。

方法:将此问题分为两种情况:
第一个是当前在其中一个内核中运行相同类型的任务时。然后,只需将即将到来的任务分配给该核心。例如 1,在 i = 3(第三个任务)时,当第 1 类任务出现时,我们可以将该任务分配给之前执行第 1 类任务的那个核心。其成本为 0 单位。

第二种情况是相同类型的任务没有在任何内核中运行。那么,可能有两种可能。子案例 1 是,如果有至少一个空闲内核,则将即将到来的任务分配给该内核。

子案例 2 是,如果没有空闲内核,那么我们必须停止处理一种类型的任务,释放一个内核并在该内核中分配即将到来的任务,以便将来的成本变得最小。为了最小化成本,我们应该停止一种将来再也不会发生的任务。如果每个正在进行的任务在未来至少再次发生一次,那么我们应该停止在所有当前正在进行的任务中最后再次发生的任务(这是一种贪婪的方法和意志任务)。

例如 2 : 在 i = 4(第四个任务),类型 3 任务,当前正在进行的类型 1 和类型 2 任务在两个核心中,我们可以停止任务类型 1 或任务类型 2 以启动任务类型 3。但我们将停止任务类型 1 作为类型 1 任务在类型二任务之后重新发生。

C++
// C++ Program to fid out minimum
// cost to process m tasks
#include 
 
using namespace std;
 
// Function to find out the farthest
// position where one of the currently
// ongoing tasks will rehappen.
int find(vector arr, int pos,
         int m, vector isRunning)
{
 
    // Iterate form last to current
    // position and find where the
    // task will happen next.
    vector d(m + 1, 0);
    for (int i = m; i > pos; i--)
    {
        if (isRunning[arr[i]])
            d[arr[i]] = i;
    }
 
    // Find out maximum of all these
    // positions and it is the
    // farthest position.
    int maxipos = 0;
    for (int ele : d)
        maxipos = max(ele, maxipos);
 
    return maxipos;
}
 
// Function to find out minimum cost to
// process all the tasks
int mincost(int n, int m, vector arr)
{
 
    // freqarr[i][j] denotes the frequency
    // of type j task after position i
    // like in array {1, 2, 1, 3, 2, 1}
    // frequency of type 1 task after
    // position 0 is 2. So, for this
    // array freqarr[0][1] = 2. Here,
    // i can range in between 0 to m-1 and
    // j can range in between 0 to m(though
    // there is not any type 0 task).
    vector > freqarr(m);
 
    // Fill up the freqarr vector from
    // last to first. After m-1 th position
    // frequency of all type of tasks will be
    // 0. Then at m-2 th position only frequency
    // of arr[m-1] type task will be increased
    // by 1. Again, in m-3 th position only
    // frequency of type arr[m-2] task will
    // be increased by 1 and so on.
    vector newvec(m + 1, 0);
    freqarr[m - 1] = newvec;
    for (int i = m - 2; i >= 0; i--)
    {
        vector nv;
        nv = freqarr[i + 1];
        nv[arr[i + 1]] += 1;
        freqarr[i] = nv;
    }
 
    // isRunning[i] denotes whether type i
    // task is currently running in one
    // of the cores.
    // At the beginning no tasks are
    // running so all values are false.
    vector isRunning(m + 1, false);
 
    // cost denotes total cost to assign tasks
    int cost = 0;
 
    // truecount denotes number of occupied cores
    int truecount = 0;
 
    // iterate through each task and find the
    // total cost.
    for (int i = 0; i < m; i++) {
 
        // ele denotes type of task.
        int ele = arr[i];
 
        // Case 1: if smae type of task is
        // currently running cost for this
        // is 0.
        if (isRunning[ele] == true)
            continue;
 
        // Case 2: same type of task is not
        // currently running.
        else {
 
            // Subcase 1: if there is at least
            // one free core then assign this task
            // to that core at a cost of 1 unit.
            if (truecount < n) {
                cost += 1;
                truecount += 1;
                isRunning[ele] = true;
            }
 
            // Subcase 2: No core is free
            else {
 
                // here we will first find the minimum
                // frequency among all the ongoing tasks
                // in future.
                // If the minimum frequency is 0 then
                // there is at least one ongoing task
                // which will not occur again. Then we just
                // stop tha task.
                // If minimum frequency is >0 then, all the
                // tasks will occur at least once in future.
                // we have to find out which of these will
                // rehappen last among the all ongoing tasks.
 
                // set minimum frequency to a big number
                int mini = 100000;
 
                // set index of minimum frequency task to 0.
                int miniind = 0;
 
                // find the minimum frequency task type(miniind)
                // and frequency(mini).
                for (int j = 1; j <= m; j++) {
                    if (isRunning[j] && mini > freqarr[i][j]) {
                        mini = freqarr[i][j];
                        miniind = j;
                    }
                }
 
                // If minimum frequency is zero then just stop
                // the task and start the present task in that
                // core. Cost for this is 1 unit.
                if (mini == 0) {
                    isRunning[miniind] = false;
                    isRunning[ele] = true;
                    cost += 1;
                }
 
                // If minimum frequency is nonzero then find
                // the farthest position where one of the
                // ongoing task will rehappen.
                // Stop that task and start present task
                // in that core.
                else {
 
                    // find out the farthest position using
                    // find function
                    int farpos = find(arr, i, m, isRunning);
                    isRunning[arr[farpos]] = false;
                    isRunning[ele] = true;
                    cost += 1;
                }
            }
        }
    }
    // return total cost
    return cost;
}
 
// Driver Program
int main()
{
    // Test case 1
    int n1 = 3;
    int m1 = 6;
    vector arr1{ 1, 2, 1, 3, 4, 1 };
    cout << mincost(n1, m1, arr1) << endl;
 
    // Test case 2
    int n2 = 2;
    int m2 = 6;
    vector arr2{ 1, 2, 1, 3, 2, 1 };
    cout << mincost(n2, m2, arr2) << endl;
 
    // Test case 3
    int n3 = 3;
    int m3 = 31;
    vector arr3{ 7, 11, 17, 10, 7, 10, 2, 9,
                      2, 18, 8, 10, 20, 10, 3, 20,
                      17, 17, 17, 1, 15, 10, 8, 3,
                       3, 18, 13, 2, 10, 10, 11 };
    cout << mincost(n3, m3, arr3) << endl;
 
    return 0;
}


Java
// Java program to fid out minimum
// cost to process m tasks
import java.util.*;
 
class GFG{
 
// Function to find out the farthest
// position where one of the currently
// ongoing tasks will rehappen.
static int find(int[] arr, int pos, int m,
                boolean[] isRunning)
{
     
    // Iterate form last to current
    // position and find where the
    // task will happen next.
    int[] d = new int[m + 1];
    for(int i = m - 1; i > pos; i--)
    {
        if (isRunning[arr[i]])
            d[arr[i]] = i;
    }
 
    // Find out maximum of all these
    // positions and it is the
    // farthest position.
    int maxipos = 0;
    for(int ele : d)
        maxipos = Math.max(ele, maxipos);
 
    return maxipos;
}
 
// Function to find out minimum cost to
// process all the tasks
static int mincost(int n, int m, int[] arr)
{
     
    // freqarr[i][j] denotes the frequency
    // of type j task after position i
    // like in array {1, 2, 1, 3, 2, 1}
    // frequency of type 1 task after
    // position 0 is 2. So, for this
    // array freqarr[0][1] = 2. Here,
    // i can range in between 0 to m-1 and
    // j can range in between 0 to m(though
    // there is not any type 0 task).
    @SuppressWarnings("unchecked")
    Vector[] freqarr = new Vector[m];
    for(int i = 0; i < freqarr.length; i++)
        freqarr[i] = new Vector();
         
    // Fill up the freqarr vector from
    // last to first. After m-1 th position
    // frequency of all type of tasks will be
    // 0. Then at m-2 th position only frequency
    // of arr[m-1] type task will be increased
    // by 1. Again, in m-3 th position only
    // frequency of type arr[m-2] task will
    // be increased by 1 and so on.
    int[] newvec = new int[m + 1];
    for(int i = 0; i < m + 1; i++)
        freqarr[m - 1].add(newvec[i]);
         
    for(int i = m - 2; i > 0; i--)
    {
        Vector nv = new Vector<>();
        nv = freqarr[i + 1];
        nv.insertElementAt(arr[i + 1] + 1,
                           arr[i + 1]);
        freqarr[i] = nv;
    }
 
    // isRunning[i] denotes whether type i
    // task is currently running in one
    // of the cores.
    // At the beginning no tasks are
    // running so all values are false.
    boolean[] isRunning = new boolean[m + 1];
 
    // cost denotes total cost to assign tasks
    int cost = 0;
 
    // truecount denotes number of occupied cores
    int truecount = 0;
 
    // Iterate through each task and find the
    // total cost.
    for(int i = 0; i < m; i++)
    {
         
        // ele denotes type of task.
        int ele = arr[i];
 
        // Case 1: if smae type of task is
        // currently running cost for this
        // is 0.
        if (isRunning[ele] == true)
            continue;
 
        // Case 2: same type of task is not
        // currently running.
        else
        {
             
            // Subcase 1: if there is at least
            // one free core then assign this task
            // to that core at a cost of 1 unit.
            if (truecount < n)
            {
                cost += 1;
                truecount += 1;
                isRunning[ele] = true;
            }
 
            // Subcase 2: No core is free
            else
            {
                 
                // Here we will first find the minimum
                // frequency among all the ongoing tasks
                // in future.
                // If the minimum frequency is 0 then
                // there is at least one ongoing task
                // which will not occur again. Then we just
                // stop tha task.
                // If minimum frequency is >0 then, all the
                // tasks will occur at least once in future.
                // we have to find out which of these will
                // rehappen last among the all ongoing tasks.
 
                // Set minimum frequency to a big number
                int mini = 100000;
 
                // Set index of minimum frequency task to 0.
                int miniind = 0;
                 
                // Find the minimum frequency task
                // type(miniind) and frequency(mini).
                for(int j = 0; j <= m; j++)
                {
                    if (isRunning[j] && mini >
                          freqarr[i].get(j))
                    {
                        mini = freqarr[i].get(j);
                        miniind = j;
                    }
                }
 
                // If minimum frequency is zero then
                // just stop the task and start the
                // present task in that core. Cost
                // for this is 1 unit.
                if (mini == 0)
                {
                    isRunning[miniind] = false;
                    isRunning[ele] = true;
                    cost += 1;
                }
 
                // If minimum frequency is nonzero
                // then find the farthest position
                // where one of the ongoing task
                // will rehappen.Stop that task
                // and start present task in that
                // core.
                else
                {
                     
                    // Find out the farthest position
                    // using find function
                    int farpos = find(arr, i, m,
                                      isRunning);
                    isRunning[arr[farpos]] = false;
                    isRunning[ele] = true;
                    cost += 1;
                }
            }
        }
    }
     
    // Return total cost
    return cost;
}
 
// Driver code
public static void main(String[] args)
{
     
    // Test case 1
    int n1 = 3;
    int m1 = 6;
    int[] arr1 = { 1, 2, 1, 3, 4, 1 };
    System.out.print(mincost(n1, m1, arr1) + "\n");
 
    // Test case 2
    int n2 = 2;
    int m2 = 6;
    int[] arr2 = { 1, 2, 1, 3, 2, 1 };
    System.out.print(mincost(n2, m2, arr2) + "\n");
 
    // Test case 3
    int n3 = 3;
    int m3 = 31;
    int[] arr3 = { 7, 11, 17, 10, 7, 10,
                   2, 9, 2, 18, 8, 10,
                   20, 10, 3, 20, 17, 17,
                   17, 1, 15, 10, 8, 3,
                   3, 18, 13, 2, 10, 10, 11 };
 
    System.out.print(mincost(n3, m3 - 8, arr3) + "\n");
}
}
 
// This code is contributed by Amit Katiyar


Python3
# Python3 Program to fid out
# minimum cost to process m tasks
 
# Function to find out the farthest
# position where one of the currently
# ongoing tasks will rehappen.
def find(arr, pos, m, isRunning):
 
    # Iterate form last to current
    # position and find where the
    # task will happen next.
    d = [0] * (m + 1)
    for i in range(m - 1, pos, -1):
     
        if isRunning[arr[i]]:
            d[arr[i]] = i
     
    # Find out maximum of all these positions
    # and it is the farthest position.
    maxipos = 0
    for ele in d:
        maxipos = max(ele, maxipos)
 
    return maxipos
 
# Function to find out minimum
# cost to process all the tasks
def mincost(n, m, arr):
 
    # freqarr[i][j] denotes the frequency
    # of type j task after position i
    # like in array 1, 2, 1, 3, 2, 1
    # frequency of type 1 task after
    # position 0 is 2. So, for this
    # array freqarr[0][1] = 2. Here,
    # i can range in between 0 to m-1 and
    # j can range in between 0 to m(though
    # there is not any type 0 task).
    freqarr = [[] for i in range(m)]
 
    # Fill up the freqarr vector from
    # last to first. After m-1 th position
    # frequency of all type of tasks will be
    # 0. Then at m-2 th position only frequency
    # of arr[m-1] type task will be increased
    # by 1. Again, in m-3 th position only
    # frequency of type arr[m-2] task will
    # be increased by 1 and so on.
    newvec = [0] * (m + 1)
    freqarr[m - 1] = newvec[:]
    for i in range(m - 2, -1, -1):
     
        nv = freqarr[i + 1][:]
        nv[arr[i + 1]] += 1
        freqarr[i] = nv[:]
     
    # isRunning[i] denotes whether type i
    # task is currently running in one
    # of the cores.
    # At the beginning no tasks are
    # running so all values are false.
    isRunning = [False] * (m + 1)
 
    # cost denotes total cost to assign tasks
    cost = 0
 
    # truecount denotes number of occupied cores
    truecount = 0
 
    # iterate through each task
    # and find the total cost.
    for i in range(0, m):
 
        # ele denotes type of task.
        ele = arr[i]
 
        # Case 1: if smae type of task is
        # currently running cost for this is 0.
        if isRunning[ele] == True:
            continue
 
        # Case 2: same type of task
        # is not currently running.
        else:
 
            # Subcase 1: if there is at least
            # one free core then assign this task
            # to that core at a cost of 1 unit.
            if truecount < n:
                cost += 1
                truecount += 1
                isRunning[ele] = True
             
            # Subcase 2: No core is free
            else:
 
                # here we will first find the minimum
                # frequency among all the ongoing tasks
                # in future.
                # If the minimum frequency is 0 then
                # there is at least one ongoing task
                # which will not occur again. Then we just
                # stop tha task.
                # If minimum frequency is >0 then, all the
                # tasks will occur at least once in future.
                # we have to find out which of these will
                # rehappen last among the all ongoing tasks.
 
                # set minimum frequency to a big number
                mini = 100000
 
                # set index of minimum frequency task to 0.
                miniind = 0
 
                # find the minimum frequency task
                # type(miniind) and frequency(mini).
                for j in range(1, m + 1):
                    if isRunning[j] and mini > freqarr[i][j]:
                        mini = freqarr[i][j]
                        miniind = j
 
                # If minimum frequency is zero then just stop
                # the task and start the present task in that
                # core. Cost for this is 1 unit.
                if mini == 0:
                    isRunning[miniind] = False
                    isRunning[ele] = True
                    cost += 1
                 
                # If minimum frequency is nonzero then find
                # the farthest position where one of the
                # ongoing task will rehappen.
                # Stop that task and start present task
                # in that core.
                else:
 
                    # find out the farthest position
                    # using find function
                    farpos = find(arr, i, m, isRunning)
                    isRunning[arr[farpos]] = False
                    isRunning[ele] = True
                    cost += 1
                 
    # return total cost
    return cost
 
# Driver Code
if __name__ == "__main__":
 
    # Test case 1
    n1, m1 = 3, 6
    arr1 = [1, 2, 1, 3, 4, 1]
    print(mincost(n1, m1, arr1))
 
    # Test case 2
    n2, m2 = 2, 6
    arr2 = [1, 2, 1, 3, 2, 1]
    print(mincost(n2, m2, arr2))
 
    # Test case 3
    n3, m3 = 3, 31
    arr3 = [7, 11, 17, 10, 7, 10, 2, 9,
            2, 18, 8, 10, 20, 10, 3, 20,
            17, 17, 17, 1, 15, 10, 8, 3,
            3, 18, 13, 2, 10, 10, 11]
             
    print(mincost(n3, m3, arr3))
 
# This code is contributed by Rituraj Jain


输出:
4
4
18




时间复杂度: O(m^2)
空间复杂度: O(m^2),(存储频率)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程