📌  相关文章
📜  删除数组所需的最少操作

📅  最后修改于: 2022-05-13 01:57:46.799000             🧑  作者: Mango

删除数组所需的最少操作

给定一个N为偶数的整数数组。数组上允许进行两种操作。

  1. 将任意元素 A[i] 的值加 1。
  2. 如果数组中的两个相邻元素是连续的素数,则删除这两个元素。也就是说,A[i] 是一个素数,A[i+1] 是下一个素数。

任务是找到删除数组中所有元素所需的最少操作次数。
例子:

Input  : arr[] = { 1, 2, 4, 3 } 
Output : 5
Minimum 5 operation are required.
1. Increase the 2nd element by 1
{ 1, 2, 4, 3 } -> { 1, 3, 4, 3 }
2. Increase the 3rd element by 1
{ 1, 3, 4, 3 } -> { 1, 3, 5, 3 }
3. Delete the 2nd and 3rd element
{ 1, 3, 5, 3 } -> { 1, 3 }
4. Increase the 1st element by 1
{ 1, 3 } -> { 2, 3 }
5. Delete the 1st and 2nd element
{ 2, 3 } -> { }

Input : arr[] = {10, 12}
Output : 3

要删除数字,我们必须将两个数字转换为两个连续的素数。如何计算将两个数字a、b转换为两个连续素数的最小成本,其中成本是两个数字的增量数?
我们使用筛子预先计算素数,然后使用数组找到第一个不大于a的素数p和第一个大于p的素数。
一旦我们计算了两个最接近的素数,我们就使用动态规划来解决这个问题。令 dp[i][j] 为清除子数组 A[i, j] 的最小成本。如果数组中有两个数字,答案很容易找到。现在,对于 N > 2,尝试位置 k > i 处的任何元素作为 A[i] 的对,这样在 A[i] 和 A[k] 之间存在偶数个来自 A[i, j] 的元素。对于固定的k,清除A[i, j]的最小成本,即dp[i][j],等于dp[i + 1][k – 1] + dp[k + 1][j] + (将 A[i] 和 A[k] 转换为连续素数的成本)。我们可以通过迭代所有可能的 k 来计算答案。
以下是上述方法的实现:

C++
// C++ program to count minimum operations
// required to remove an array
#include
#define MAX 100005
using namespace std;
 
// Return the cost to convert two numbers into
// consecutive prime number.
int cost(int a, int b, int prev[], int nxt[])
{
    int sub = a + b;
 
    if (a <= b && prev[b-1] >= a)
        return nxt[b] + prev[b-1] - a - b;
 
    a = max(a, b);
    a = nxt[a];
    b = nxt[a + 1];
 
    return a + b - sub;
}
 
// Sieve to store next and previous prime
// to a number.
void sieve(int prev[], int nxt[])
{
    int pr[MAX] = { 0 };
 
    pr[1] = 1;
    for (int i = 2; i < MAX; i++)
    {
        if (pr[i])
            continue;
 
        for (int j = i*2; j < MAX; j += i)
            pr[j] = 1;
    }
 
    // Computing next prime each number.
    for (int i = MAX - 1; i; i--)
    {
        if (pr[i] == 0)
            nxt[i] = i;
        else
            nxt[i] = nxt[i+1];
    }
 
    // Computing previous prime each number.
    for (int i = 1; i < MAX; i++)
    {
        if (pr[i] == 0)
            prev[i] = i;
        else
            prev[i] = prev[i-1];
    }
}
 
// Return the minimum number of operation required.
int minOperation(int arr[], int nxt[], int prev[], int n)
{
    int dp[n + 5][n + 5] = { 0 };
 
    // For each index.
    for (int r = 0; r < n; r++)
    {
        // Each subarray.
        for (int l = r-1; l >= 0; l -= 2)
        {
            dp[l][r] = INT_MAX;
 
            for (int ad = l; ad < r; ad += 2)
                dp[l][r] = min(dp[l][r], dp[l][ad] +
                          dp[ad+1][r-1] +
                          cost(arr[ad], arr[r], prev, nxt));
        }
    }
 
    return dp[0][n - 1] + n/2;
}
 
// Driven Program
int main()
{
    int arr[] = { 1, 2, 4, 3 };
    int n = sizeof(arr)/sizeof(arr[0]);
 
    int nxt[MAX], prev[MAX];
    sieve(prev, nxt);
 
    cout << minOperation(arr, nxt, prev, n);
 
    return 0;
}


Java
// Java program to count minimum operations
// required to remove an array
class GFG
{
 
static final int MAX = 100005;
 
// Return the cost to convert two
// numbers into consecutive prime number.
static int cost(int a, int b,
                int prev[], int nxt[])
{
    int sub = a + b;
 
    if (a <= b && prev[b - 1] >= a)
    {
        return nxt[b] + prev[b - 1] - a - b;
    }
 
    a = Math.max(a, b);
    a = nxt[a];
    b = nxt[a + 1];
 
    return a + b - sub;
}
 
// Sieve to store next and previous
// prime to a number.
static void sieve(int prev[], int nxt[])
{
    int pr[] = new int[MAX];
 
    pr[1] = 1;
    for (int i = 2; i < MAX; i++)
    {
        if (pr[i] == 1)
        {
            continue;
        }
 
        for (int j = i * 2; j < MAX; j += i)
        {
            pr[j] = 1;
        }
    }
 
    // Computing next prime each number.
    for (int i = MAX - 2; i > 0; i--)
    {
        if (pr[i] == 0)
        {
            nxt[i] = i;
        }
        else
        {
            nxt[i] = nxt[i + 1];
        }
    }
 
    // Computing previous prime each number.
    for (int i = 1; i < MAX; i++)
    {
        if (pr[i] == 0)
        {
            prev[i] = i;
        }
        else
        {
            prev[i] = prev[i - 1];
        }
    }
}
 
// Return the minimum number
// of operation required.
static int minOperation(int arr[], int nxt[],
                        int prev[], int n)
{
    int dp[][] = new int[n + 5][n + 5];
 
    // For each index.
    for (int r = 0; r < n; r++)
    {
        // Each subarray.
        for (int l = r - 1; l >= 0; l -= 2)
        {
            dp[l][r] = Integer.MAX_VALUE;
 
            for (int ad = l; ad < r; ad += 2)
            {
                dp[l][r] = Math.min(dp[l][r], dp[l][ad] +
                                    dp[ad + 1][r - 1] +
                                    cost(arr[ad], arr[r],
                                            prev, nxt));
            }
        }
    }
 
    return dp[0][n - 1] + n / 2;
}
 
// Driver Code
public static void main(String args[])
{
    int arr[] = {1, 2, 4, 3};
    int n = arr.length;
 
    int nxt[] = new int[MAX], prev[] = new int[MAX];
    sieve(prev, nxt);
 
    System.out.println(minOperation(arr, nxt, prev, n));
}
}
 
// This code is contributed by 29AjayKumar


Python3
# Python 3 program to count minimum
# operations required to remove an array
MAX = 100005
INT_MAX = 10000000
 
# Return the cost to convert two numbers
# into consecutive prime number.
def cost(a, b, prev, nxt):
    sub = a + b
    if (a <= b and prev[b - 1] >= a):
        return nxt[b] + prev[b - 1] - a - b
 
    a = max(a, b)
    a = nxt[a]
    b = nxt[a + 1]
    return a + b - sub
 
# Sieve to store next and previous
# prime to a number.
def sieve(prev, nxt):
    pr = [0 for i in range(MAX)]
 
    pr[1] = 1
    for i in range(1, MAX):
        if (pr[i]):
            continue
        for j in range(i * 2, MAX, i):
            pr[j] = 1
 
    # Computing next prime each number.
    for i in range(MAX - 2, -1, -1):
        if (pr[i] == 0):
            nxt[i] = i
        else:
            nxt[i] = nxt[i + 1]
 
    # Computing previous prime each number.
    for i in range(1, MAX):
        if (pr[i] == 0):
            prev[i] = i
        else:
            prev[i] = prev[i - 1]
 
# Return the minimum number of
# operation required.
def minOperation(arr, nxt, prev, n):
    dp = [[0 for i in range(n + 5)]
             for i in range(n + 5)]
 
    # For each index.
    for r in range(n):
         
        # Each subarray.
        for l in range(r - 1, -1, -2):
            dp[l][r] = INT_MAX;
 
            for ad in range(l, r, 2):
                dp[l][r] = min(dp[l][r], dp[l][ad] +
                               dp[ad + 1][r - 1] +
                               cost(arr[ad], arr[r],
                                         prev, nxt))
    return dp[0][n - 1] + n // 2
 
# Driver Code
arr = [1, 2, 4, 3]
n = len(arr)
 
nxt = [0 for i in range(MAX)]
prev = [0 for i in range(MAX)]
sieve(prev, nxt)
print(minOperation(arr, nxt, prev, n))
 
# This code is contributed by sahishelangia


C#
// C# program to count minimum operations
// required to remove an array
using System;
class GFG
{
 
static int MAX = 100005;
 
// Return the cost to convert two
// numbers into consecutive prime number.
static int cost(int a, int b,
                int[] prev, int[] nxt)
{
    int sub = a + b;
 
    if (a <= b && prev[b - 1] >= a)
    {
        return nxt[b] + prev[b - 1] - a - b;
    }
 
    a = Math.Max(a, b);
    a = nxt[a];
    b = nxt[a + 1];
 
    return a + b - sub;
}
 
// Sieve to store next and previous
// prime to a number.
static void sieve(int[] prev, int[] nxt)
{
    int[] pr = new int[MAX];
 
    pr[1] = 1;
    for (int i = 2; i < MAX; i++)
    {
        if (pr[i] == 1)
        {
            continue;
        }
 
        for (int j = i * 2; j < MAX; j += i)
        {
            pr[j] = 1;
        }
    }
 
    // Computing next prime each number.
    for (int i = MAX - 2; i > 0; i--)
    {
        if (pr[i] == 0)
        {
            nxt[i] = i;
        }
        else
        {
            nxt[i] = nxt[i + 1];
        }
    }
 
    // Computing previous prime each number.
    for (int i = 1; i < MAX; i++)
    {
        if (pr[i] == 0)
        {
            prev[i] = i;
        }
        else
        {
            prev[i] = prev[i - 1];
        }
    }
}
 
// Return the minimum number
// of operation required.
static int minOperation(int[] arr, int[] nxt,
                        int[] prev, int n)
{
    int[,] dp = new int[n + 5, n + 5];
 
    // For each index.
    for (int r = 0; r < n; r++)
    {
        // Each subarray.
        for (int l = r - 1; l >= 0; l -= 2)
        {
            dp[l, r] = Int32.MaxValue;
 
            for (int ad = l; ad < r; ad += 2)
            {
                dp[l, r] = Math.Min(dp[l, r], dp[l, ad] +
                                    dp[ad + 1, r - 1] +
                                    cost(arr[ad], arr[r],
                                            prev, nxt));
            }
        }
    }
 
    return dp[0, n - 1] + n / 2;
}
 
// Driver Code
public static void Main()
{
    int[] arr = {1, 2, 4, 3};
    int n = arr.Length;
 
    int[] nxt = new int[MAX];
    int[] prev = new int[MAX];
    sieve(prev, nxt);
 
    Console.WriteLine(minOperation(arr, nxt, prev, n));
}
}
 
// This code is contributed by Mukul Singh


PHP
= $a)
        return $nxt[$b] + $prev[$b-1] - $a - $b;
  
    $a = max($a, $b);
    $a = $nxt[$a];
    $b = $nxt[$a + 1];
  
    return $a + $b - $sub;
}
  
// Sieve to store next and previous prime
// to a number.
function sieve(&$prev, &$nxt)
{
    global $MAX;
    $pr = array_fill(0,$MAX,NULL);
  
    $pr[1] = 1;
    for ($i = 2; $i < $MAX; $i++)
    {
        if ($pr[$i])
            continue;
  
        for ($j = $i*2; $j < $MAX; $j += $i)
            $pr[$j] = 1;
    }
  
    // Computing next prime each number.
    for ($i = $MAX - 1; $i; $i--)
    {
        if ($pr[$i] == 0)
            $nxt[$i] = $i;
        else
            $nxt[$i] = $nxt[$i+1];
    }
  
    // Computing previous prime each number.
    for ($i = 1; $i < $MAX; $i++)
    {
        if ($pr[$i] == 0)
            $prev[$i] = $i;
        else
            $prev[$i] = $prev[$i-1];
    }
}
  
// Return the minimum number of operation required.
function minOperation(&$arr, &$nxt, &$prev, $n)
{
    global $MAX;
    $dp = array_fill(0,($n + 5),array_fill(0,($n + 5),NULL));
  
    // For each index.
    for ($r = 0; $r < $n; $r++)
    {
        // Each subarray.
        for ($l = $r-1; $l >= 0; $l -= 2)
        {
            $dp[$l][$r] = PHP_INT_MAX;
  
            for ($ad = $l; $ad < $r; $ad += 2)
                $dp[$l][$r] = min($dp[$l][$r], $dp[$l][$ad] +
                          $dp[$ad+1][$r-1] +
                          cost($arr[$ad], $arr[$r], $prev, $nxt));
        }
    }
  
    return $dp[0][$n - 1] + $n/2;
}
  
// Driven Program
 
$arr = array( 1, 2, 4, 3 );
$n = sizeof($arr)/sizeof($arr[0]);
 
$nxt = array_fill(0,$MAX,NULL);
$prev = array_fill(0,$MAX,NULL);
sieve($prev, $nxt);
 
echo minOperation($arr, $nxt, $prev, $n);
 
return 0;
?>


Javascript


输出:

5