2017網絡新生賽2303回文字串心得
題目描述:
回文詞是一種對稱的字符串。任意給定一個字符串,通過插入若幹字符,都可以變成回文詞。此題的任務是,求出將給定字符串變成回文詞所需要插入的最少字符數。
比如 “Ab3bd”插入2個字符後可以變成回文詞“dAb3bAd”或“Adb3bdA”,但是插入少於2個的字符無法變成回文詞。
註:此問題區分大小寫.
輸入描述:
一個字符串(0<strlen<=1000)
輸出描述:
有且只有一個整數,即最少插入字符數
輸入樣例:
Ab3bd
輸出樣例:
2
分析:
這是一道有關於DP的LCS問題,也就是最長公共子序列問題。
我們先看網上的一種動規方程解出的代碼,這個代碼我還沒有完全想通,所以暫時先上代碼,希望大家能盡量去理解這個動規方程。
代碼:
#include <stdio.h>
#include <string.h>
int a1[1000][1000];
int min1(int a,int b)
{
return a < b ? a : b;
}
int main(void)
{
int i,j,p;
char c[1001];
scanf ("%s",c);
p = strlen(c);
memset(a1,0,sizeof(a1));
for (i = p - 1; i >= 0; i--)
{
for (j = i + 1; j < p; j++)
{
if(c[i] == c[j])
{
a1[i][j] = a1[i + 1][j - 1];
}
else
{
a1[i][j] = min1(a1[i + 1][j],a1[i][j - 1]) + 1;
}
printf("%d ",a1[i][j]);
}
printf("\n");
}
printf ("%d\n",a1[0][p - 1]);
return 0;
}
解法2:
DPLCS解法。
所謂的LCS,就是指兩個字符串的最長公共子序列,比如說,Ab3bd和Abbd的最長公共子序列就是Abbd,它的長度是4,也就是說,一個字符串的子序列是可以忽略該字符串的任意一個或者多個字符的。
而對於這道題目,為了使該字符串成為一個回文串,我們需要做的是:將該字符串和它的反串進行最長子序列長度的查找。DP方程是:當c1[i] == c2[j]時,a[i][j] = a[i - 1][j - 1] + 1;否則 a[i][j] = max1(a[i - 1][j],a[i][j - 1]);
求完二維數組以後,a[p - 1][p - 1]就是該字符串和其反串最長公共子序列的長度.用p減去a[p - 1][p - 1]就是使之成為回文串所需插入的最少字符數。因為,只有除了最長公共子序列以外的字符,需要通過插入字符來使之成為回文串,從而導致整體為回文串,而我們只需要插入與除最長公共子序列以外的字符數,就能使這些字符成為回文串,從而整體成為回文串。下面上代碼:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
using namespace std;
int n;
int dp[1001][1001];
char str1[1001],str2[1001];
int main()
{
scanf("%s", str1+1);
n = strlen(str1+1);
for(int i = 1; i <= n; i++)
str2[i] = str1[n-i+1]; //做一個逆序的字符串數組
for(int i = 1; i<=n; i++)
for(int j = 1; j <= n; j++)
if(str1[i] == str2[j])
dp[i][j] = dp[i-1][j-1] + 1; //最長公共自序列匹配
else
dp[i][j] = max(dp[i-1][j], dp[i][j-1]); //不匹配的往下匹配狀態
printf("%d\n", n-dp[n][n]); //字符串長度減去匹配出的最長公共自序列的值
return 0; //即需要添加的字符數
}
2017網絡新生賽2303回文字串心得