📜  在切换成本的情况下处理m个任务的最低成本

📅  最后修改于: 2021-04-25 00:37:20             🧑  作者: 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 –无。
在自由核心->成本1单位中分配类型3的任务。状态:A – 1,B – 2,C – 3。

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

状态:A – 1,B – 4,C –3。现在,将类型1任务加载到正在运行类型1任务的核心A中->成本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个单位。

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

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

子情况2是,如果没有可用的核心,那么我们必须停止处理一种类型的任务,释放一个核心,并在该核心中分配即将到来的任务,以使将来的成本降至最低。为了最大程度地降低成本,我们应该停止一种以后不会再发生的任务。如果每个正在进行的任务将来至少发生一次,那么我们应该停止该任务,该任务将在所有当前正在进行的任务中最后一次发生(这是一种贪婪的方法,并且会执行任务)。

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

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),(存储频率)