Palindrome subsequence HDU - 4632 区间dp|记忆化搜索

 
 

// 区间dp
import java.util.Scanner;

/**
 *
 * @author CN
 */
public class main {

    static int mod = 10007;
    static String l;
    static int[][] dp = new int[1010][1010];
    public static void main(String[] args)
    {
        // TODO code application logic here
        int t;
        Scanner sc = new Scanner(System.in);
        t = sc.nextInt();
        
        for(int i=1;i<=t;i++){ 
            l = sc.next();
            for(int p=0;p<1010;p++){
                for(int q=0;q<1010;q++)
                    dp[p][q] = 0;
            }
            
            for(int r=0;r<l.length();r++)
                dp[r][r] = 1;
            
            for(int len = 1;len<l.length();len++){
                for(int p=0;p<l.length();p++){
                    for(int q=p+len;q<l.length();q++){
                        dp[p][q] = dp[p+1][q] + dp[p][q-1];
                        if(l.charAt(p)!=l.charAt(q))dp[p][q]-=dp[p+1][q-1];
                        else dp[p][q]++;
                        dp[p][q]=(dp[p][q]+mod)%mod; 
                        break;
                    }
                }
            }
            System.out.println("Case "+i+": "+dp[0][l.length()-1]);            
        }
    }
}



import java.util.Scanner;
// 记忆化搜索写法

public class Main {

    static int mod = 10007;
    static String l;
    static int[][] dp = new int[1010][1010];
    static int dfs(int le,int rt){
        if(le>rt)return 0;
        if(le==rt)return 1;
        if(dp[le][rt]!=-1)return dp[le][rt];
        
        dp[le][rt] = (dfs(le+1,rt)+dfs(le,rt-1) - dfs(le+1,rt-1)+ mod)%mod;
        if(l.charAt(le)==l.charAt(rt))
            dp[le][rt] = (dfs(le,rt)+dfs(le+1,rt-1)+1)%mod;
        return dp[le][rt];
    }
    public static void main(String[] args)
    {
        int t;
        Scanner sc = new Scanner(System.in);
        t = sc.nextInt();
        
        for(int i=1;i<=t;i++){ 
            l = sc.next();
            for(int p=0;p<l.length();p++){
                for(int q=0;q<l.length();q++)
                    dp[p][q] = -1;
            }       
            System.out.println("Case "+i+": "+dfs(0,l.length()-1));            
        }
    }
}

题意就是在一个字符串计数任意可能的回文子串 计算所有子串的数量 每个字串要求先后顺序相同

思路:
也就是根据子串的左右边界定义一个子串用dp[i][j]表示从i到j的所有的回文子串的数量
分析可知 dp[i][j] 可以由两个状态转移得来 也就是dp[i+1][j] 和 dp[i][j-1]之和得来
如果i处的字符不等于j处的字符 需要减去一个公共部分dp[i+1][j-1] 因为以上两个状态中的任意一个状态都会包含这个状态的
信息 所以会多一个dp[i+1][j-1] 不妨减去
如果i字符等于j处字符 也就是可以构成一个新的回文子串 这个数量关系 仍然是dp[i-1][j-1]得来
或者使用记忆化搜索去做 一开始可以把所有值初始化为一个不可能值 比如-1如果这个值搜索到的时候非-1 也就是已经搜索过了
可以直接返回

注意有减法的取模操作 +mod 再%mod
一开始Case后面多了个# WA了好几发 。。。坑啊。。。

猜你喜欢

转载自blog.csdn.net/qq_33859479/article/details/80314462