Superpalindromlar#470

Superpalindromlar (Həll təhlili)

Tutaq ki, — giriş sətri. Alt sətr s_i ... s_j palindromdur, əgər ən azı bir şərt yerinə yetirilirsə:

Funksiya IsPal təyin edək, hansı ki, s_i ... s_j alt sətri palindromdursa, , əks halda qaytarır.

Algoritmanın işləmə sürətini artırmaq üçün IsPal(i, j) funksiyasının qiymətlərini iki ölçülü massivin pal[i][j] hüceyrələrində saxlayacağıq.

Sətr superpalindrom adlanır, əgər onu bir və ya bir neçə palindromun konkatenasiyası formasında təqdim etmək olarsa. Məsələn, aşağıdakı sətrlər superpalindromlardır:

Deyək ki,

dp[i][j] = \begin{cases} 1, & \text{s alternativ } s_i \ldots s_j\ (i < j) \text{ superpalindrom,} \\ 0, & \text{əks halda}. \end{cases}

Burada nəzərdə tutulur ki, i < j, yəni alt sətr uzunluğu ən azı iki.

Baza halları qeyd edək:

dp[i][j] = 0~də~i ≥ j

Əgər alt sətr s_i ... s_j palindromdursa və uzunluğu iki və daha çoxdur, o avtomatik olaraq superpalindrom olur (çünki bir palindromdan ibarətdir). Buna görə indekslərin bütün cütləri üçün , burada 0 \le i < j < n, əgər alt sətr s_i ... s_j palindromdursa, dərhal dp[i][j] = 1 qura bilərik.

İndi hesabı ümumi halına baxaq. Alt sətr s_i ... s_j tamamilə palindrom deyil. O halda superpalindrom ola bilər əgər onu iki hissəyə bölmək mümkündür ki, hər biri öz növbəsində superpalindrom olsun.

Bunun üçün bütün mümkün bölünmə mövqelərini nəzərdən keçirəcəyik k~(i < k < j - 1).

Məhdudiyyət k < j - 1 təmin edir ki, hər iki alt sətr

s_i ... s_k~və~s_{k+1} ... s_j

uzunluğu ən azı iki, belə ki, potensial olaraq superpalindrom ola bilər.

Əgər bəzi üçün:

alt sətr s_i ... s_j iki superpalindromların konkatenasiyası olaraq təqdim edilir. Deməli, o özü superpalindromdur və biz dp[i][j] = 1 quraşdırırıq.

Əgər heç bir uyğun üçün bu şərtlər yerinə yetirilmirsə, onda dp[i][j] sıfır olaraq qalır.

Geriyə cütlərinin sayını hesablamaq qalır, harada i < j və dp[i][j] = 1. Bu sətir , alt sətrlər superpalindrom üzərində alt sətrlərin sayıdır.

Misal

Verilmiş misal üçün — sətir "", burada superpalindrom alt sətr mövcuddur:

Sətir "" üçün superpalindrom alt sətr mövcuddur:

Algoritmin həyata keçirilməsi

İşçi massivlər elan edək.

#define MAX 1010
char s[MAX];
int dp[MAX][MAX];
int pal[MAX][MAX];

Funksiya IsPal alt sətrin s_i \ldots s_j palindrom olub olmadığını yoxlayır. Alt sətr s_i \ldots s_j palindromdur, əgər s_i = s_j və alt sətr s_{i + 1} \ldots s_{j - 1} də palindromdur.

int IsPal(int i, int j)
{
  if (i >= j) return pal[i][j] = 1;
  if (pal[i][j] != -1) return pal[i][j];
  return pal[i][j] = (s[i] == s[j]) && IsPal(i + 1,j - 1);
}

Proqramın əsas hissəsi. Giriş sətirini oxuyuruq. Onun uzunluğunu hesablayırıq.

cin >> s; n = s.size();

Massivlər və inicializasiya edirik.

memset(dp,0,sizeof(dp));
memset(pal,-1,sizeof(pal));

Bütün alt sətrləri s_i \ldots s_{i + len} sətirdən araşdırırıq uzunluqların artan sırasına görə. Əsas də alt sətrtərin dp[i][j] qiyməti daha qısa alt sətrlərin qiymətlərindən asılıdır.

for (len = 1; len < n; len++)
for (i = 0; i + len < n; i++)
{

Alt sətrin sağ sərhəddi s_i \ldots s_{i + len} j = i + len.

  j = i + len;

Əgər alt sətr s_i \ldots s_j palindromdursa, o, avtomatik olaraq superpalindrom olur.

  if (IsPal(i,j))
  {
    dp[i][j] = 1;
    continue;
  }

Əgər alt sətr s_i \ldots s_j palindrom deyilsə, onu iki superpalindromun konkatenasiyası olaraq təqdim etməyə çalışırıq.

Əgər s_i \ldots s_k və s_{k+1} \ldots s_j superpalindromlardırsa, onda s_i \ldots s_j superpalindromdur.

  for(k = i + 1; k < j - 1; k++)
    if(dp[i][k] && dp[k + 1][j])
    {
      dp[i][j] = 1;
      break;
    }
}

Superpalindromların sayını ölçürük. Bu, cüt indekslərin (i, j) sayıdır, hansı ki dp[i][j] = 1.

res = 0;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
  res += dp[i][j];

Cavabını çıxarırıq.

printf("%d\n",res);

Algoritmin həyata keçirilməsi – rekursiya

Giriş sətiri elan edək və işçi massivlər.

#define MAX 1010
string s;
int dp[MAX][MAX], pal[MAX][MAX];

Funksiya IsPal alt sətrin s_i \ldots s_j palindrom olub olmadığını yoxlayır. Alt sətr s_i \ldots s_j palindromdır əgər s_i = s_j və alt sətr s_{i + 1} \ldots s_{j - 1} də palindromdır.

int IsPal(int i, int j)
{
  if (i >= j) return pal[i][j] = 1;
  if (pal[i][j] != -1) return pal[i][j];
  return pal[i][j] = (s[i] == s[j]) && IsPal(i+1,j-1);
}

Funksiya f s_i \ldots s_j superpalindromdursa, qaytarır.

int f(int i, int j)
{

Superpalindrom daha çox simvol ehtiva etməlidir.

  if (i == j) return dp[i][j] = 0;

Əgər f artıq əvvəllər hesablanıbsa, onun qiymətini qaytarırıq.

  if (dp[i][j] != -1) return dp[i][j];

Əgər alt sətr s_i \ldots s_j~(i < j) palindromdursa, o həm də superpalindrom olur.

  if (IsPal(i,j)) return dp[i][j] = 1;

Əgər alt sətr s_i \ldots s_k~(i < k) palindromdursa, alt sətr s_{k+1} \ldots s_j~(k + 1 < j) superpalindromdursa, alt sətr s_i \ldots s_j superpalindromdur.

  for (int k = i + 1; k < j - 1; k++)
    if (IsPal(i,k) && f(k + 1,j)) return dp[i][j] = 1;

Əgər yuxarıda təsvir edilən heç bir şərtlər yerinə yetirilmirsə, alt sətr s_i \ldots s_j superpalindrom deyil.

  return dp[i][j] = 0;
}

Proqramın əsas hissəsi. Giriş sətirini oxuyurq və onun uzunluğunu hesablayırıq.

cin >> s; n = s.size();

Massivlər və inicializasiya edirik.

memset(dp,-1,sizeof(dp));
memset(pal,-1,sizeof(pal));

Superpalindromların sayını dəyişənində hesablayırıq.

res = 0;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
  res += f(i,j);

Cavabını çıxarırıq.

cout << res << endl;

Java həyata keçirilməsi

import java.util.*;

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

  static int IsPal(int i, int j)
  {
    if (i >= j) return pal[i][j] = 1;
    if (pal[i][j] != -1) return pal[i][j];
    if (s.charAt(i) == s.charAt(j) && IsPal(i+1,j-1) == 1) pal[i][j] = 1;
    else pal[i][j] = 0;
    return pal[i][j];
  }
 
  static int f(int i, int j)
  {
    if (i == j) return dp[i][j] = 0;
    if (dp[i][j] != -1) return dp[i][j];
    if (IsPal(i,j) == 1) return dp[i][j] = 1;

    for(int k = i + 1; k < j - 1; k++)
      if(IsPal(i,k) == 1 && f(k + 1,j) == 1) return dp[i][j] = 1;

    return dp[i][j] = 0;
  }
	
  public static void main(String[] args) 
  {
    Scanner con = new Scanner(System.in);
    s = con.nextLine();
    int n = s.length();
    dp = new int[n][n];
    pal = new int[n][n];
    for(int i = 0; i < n; i++)
    for(int j = 0; j < n; j++)
    {
      dp[i][j] = -1;
      pal[i][j] = -1;
    }

    int res = 0;
    for(int i = 0; i < n; i++)
    for(int j = i+1; j < n; j++)
      res += f(i,j);
    
    System.out.println(res);
    con.close();
  }
}