zoukankan      html  css  js  c++  java
  • poj 1159 Palindrome

    Palindrome
    Time Limit: 3000MS   Memory Limit: 65536K
    Total Submissions: 53525   Accepted: 18481

    Description

    A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a program which, given a string, determines the minimal number of characters to be inserted into the string in order to obtain a palindrome. 

    As an example, by inserting 2 characters, the string "Ab3bd" can be transformed into a palindrome ("dAb3bAd" or "Adb3bdA"). However, inserting fewer than 2 characters does not produce a palindrome. 

    Input

    Your program is to read from standard input. The first line contains one integer: the length of the input string N, 3 <= N <= 5000. The second line contains one string with length N. The string is formed from uppercase letters from 'A' to 'Z', lowercase letters from 'a' to 'z' and digits from '0' to '9'. Uppercase and lowercase letters are to be considered distinct.

    Output

    Your program is to write to standard output. The first line contains one integer, which is the desired minimal number.

    Sample Input

    5
    Ab3bd

    Sample Output

    2

    题目意思:给你个字符串。求最少须要加入几个字符使它变成一个回文字符串;

    解题思路:求给出的字符串和逆序的字符串的最长公共子序列,用总长度减去这个最长公共子序列的长度就可以;

    求最长公共子序列(LCS):

    字符串:s:  S1S2S3S4.......Si,t:   T1T2T3T4..........Tj;

    定义一个数组dp[i][j]表示S1S2S3S4.......Si和T1T2T3T4..........Tj所相应的最长公共子序列。

    则S1S2S3S4.......Si+1和T1T2T3T4..........Tj+1所相应的最长公共子序列可能为:

    (1)假设Si+1==Tj+1,则S1S2S3S4.......Si和T1T2T3T4..........Tj所相应的最长公共子序列+1;

    (2)S1S2S3S4.......Si+1和T1T2T3T4..........Tj所相应的最长公共子序列;

    (3)S1S2S3S4.......Si和T1T2T3T4..........Tj+1所相应的最长公共子序列。

    所以dp的状态转移方程为dp[i][j]=max( dp[i-1][j-1] + (a[i]==b[j]) , max( dp[i-1][j] , dp[i][j-1] ) )

    只是这里依然存在一个问题那就是dp数组的大小。依照上面的思路我们须要定义dp[5000+1][5000+1],而这远远会超于所给定内存的大小,为此有两种解决的方法:

    (1)将dp的类型定义为short;

    #include <iostream>
    #include <string.h>
    using namespace std;
    #define MAX 5000+1
    int n;
    char s[MAX];
    short dp[MAX+1][MAX+1];
    
    int max(int a,int b){
    	return a>b?a:b;
    }
    void solve(){
    	for (int i=0;i<n;i++){
    		dp[0][i]=0;
    		dp[i][0]=0;
    	}
    	for (int i=0;i<n;i++) 
    		for (int j=0;j<n;j++){
    			if (s[i]==s[n-1-j])
    				dp[(i+1)][j+1]=dp[i][j]+1;
    			else
    				dp[(i+1)][j+1]=max(dp[i][j+1],dp[(i+1)][j]);
    		}
    	cout<<n-dp[n][n]<<endl;
    }
    int main(){
    	
    	while (cin>>n){
    		for (int i=0;i<n;i++){
    			cin>>s[i];
    		}
    		solve();
    	}
    	return 0;
    }

    (2)採用滚动数组;

    由状态转移方程dp[i][j]=max( dp[i-1][j-1] + (a[i]==b[j]) , max( dp[i-1][j] , dp[i][j-1] ) )我们能够知道 i 所控制的行的值是由 i-1 和 i 所控制的行的值所确定的。因此我们仅仅须要每回记录前一个的。以便计算当前的,当计算下一个的时候,下一个的存放地址在最前面的地方,(简单说 先记录了a。然后又记录了b。再记录c的时候。把c的存放放到a上,即覆盖a),这样dp的定义就变成了dp[2][5000+1]。

    #include <iostream>
    #include <string.h>
    using namespace std;
    #define MAX 5000+1
    int n;
    char s[MAX];
    int dp[2][MAX+1];
    
    int max(int a,int b){
    	return a>b?a:b;
    }
    void solve(){
    	for (int i=0;i<n;i++){
    		dp[0][i]=0;
    		dp[1][i]=0;
    	}
    	for (int i=0;i<n;i++) 
    		for (int j=0;j<n;j++){
    			if (s[i]==s[n-1-j])
    				dp[(i+1)%2][j+1]=dp[i%2][j]+1;
    			else
    				dp[(i+1)%2][j+1]=max(dp[i%2][j+1],dp[(i+1)%2][j]);
    		}
    	cout<<n-dp[n%2][n]<<endl;
    }
    int main(){
    	
    	while (cin>>n){
    		for (int i=0;i<n;i++){
    			cin>>s[i];
    		}
    		solve();
    	}
    	return 0;
    }




  • 相关阅读:
    lintcode:Flip Bits 将整数A转换为B
    lintcode:strStr 字符串查找
    lintcode:Subtree 子树
    lintcode 容易题:Partition Array by Odd and Even 奇偶分割数组
    lintcode:在二叉查找树中插入节点
    lintcode:在O(1)时间复杂度删除链表节点
    lintcode:哈希函数
    lintcode:合并排序数组 II
    lintcode:合并排序数组
    lintcode:数飞机
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6892376.html
Copyright © 2011-2022 走看看