删除数组所需的最少操作
给定一个N为偶数的整数数组。数组上允许进行两种操作。
- 将任意元素 A[i] 的值加 1。
- 如果数组中的两个相邻元素是连续的素数,则删除这两个元素。也就是说,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