Sətirin kəsilməsi#7447

Sətirin kəsilməsi (Həll təhlili)

Let dp[l][r] = f(l, r) be the minimum number of characters that need to be deleted from the substring s_l ... s_r so that, by performing the allowed operations (removing two identical adjacent characters), we can obtain an empty string. Then:

However, both of these cases can be conveniently generalized as follows: to solve the problem on the segment [l; r], split it into two subsegments and [i + 1; r]~(l \le i < r) and choose the minimum value:

f(l, r) = \min_{l \le i < r} (f(l, i) + f(i + 1, r))

For example:

The answer to the problem will be dp[0][n - 1] = f(0, n - 1), where is the length of the input string.

Example

Let’s consider the example given in the problem statement. We have:

f(0, 7) = f(0, 2) + f(3, 7) = 1 + 1 = 2

Algorithm implementation

Let's declare the constants and the array.

#define MAX 101
#define INF 0x3F3F3F3F
int dp[MAX][MAX];

The function f solves the problem on the segment [l; r].

int f(int l, int r) 
{

First, consider the base cases.

  if (l > r) return 0;
  if (l == r) return 1;

If the value dp[l][r] is already computed, return it.

  if (dp[l][r] != INF) return dp[l][r];

If the characters and are equal, they do not need to be removed in advance. First, we clear the middle part of the segment; after that, these characters become adjacent and can be removed for free.

  int &res = dp[l][r];
  if (s[l] == s[r]) 
    res = min(res, f(l + 1, r - 1));	

Consider splitting the segment [l; r] into two parts: and [i + 1; r]. Solve the problem independently for each subsegment and take the minimum result.

  for (int i = l; i < r; i++)
    res = min(res, f(l, i) + f(i + 1, r));

Finally, return the computed value.

  return res;
}

The main part of the program. Read the input string.

cin >> s;
memset(dp,0x3F,sizeof(dp));

Compute and print the result f(0, n - 1), where is the length of the string .

printf("%d\n",f(0, s.size() - 1));

Java implementation

import java.util.*;

public class Main 
{
  static String s;
  static int dp[][];

  static int f(int l, int r)
  {
    if (l > r) return 0;
    if (l == r) return 1;
    if (dp[l][r] != Integer.MAX_VALUE) return dp[l][r];

    int res = dp[l][r];
    if (s.charAt(l) == s.charAt(r))
      res = Math.min(res, f(l + 1, r - 1));

    for (int i = l; i < r; i++)
      res = Math.min(res, f(l, i) + f(i + 1, r));
    return dp[l][r] = res;
  }
	
  public static void main(String[] args) 
  {
    Scanner con = new Scanner(System.in);
    s = con.nextLine();
    int n = s.length();
    dp = new int[n][n];
    for(int i = 0; i < n; i++)
    for(int j = 0; j < n; j++)
      dp[i][j] = Integer.MAX_VALUE;
 
    System.out.println(f(0, n - 1));
    con.close();
  }
}

Python implementation

Declare the constant .

INF = float('inf')

The function f solves the problem on the segment [l; r].

def f(l, r):

First, consider the base cases.

  if l > r: return 0
  if l == r: return 1

If the value dp[l][r] is already computed, return it.

  if dp[l][r] != INF:
    return dp[l][r]

If the characters and are equal, they do not need to be removed in advance. First, we clear the middle part of the segment; after that, these characters become adjacent and can be removed for free.

  res = dp[l][r]
  if s[l] == s[r]:
    res = min(res, f(l + 1, r - 1))

Consider splitting the segment [l; r] into two parts: and [i + 1; r]. Solve the problem independently for each subsegment and take the minimum result.

  for i in range(l, r):
    res = min(res, f(l, i) + f(i + 1, r))
  dp[l][r] = res
  return res

The main part of the program. Read the input string and compute its length .

s = input()
n = len(s)

Initialize the list .

dp = [[INF] * n for _ in range(n)]

Compute and print the result f(0, n - 1).

print(f(0, n - 1))