zoukankan      html  css  js  c++  java
  • UVA 10453 Make Palindrome(DP)

    Make Palindrome

    大意:求一个字符串在通过在任意位置增加一个字符使得变为一个回文串的最小操作数及打印出该回文串。

     1 #include <map>
     2 #include <stack>
     3 #include <queue>
     4 #include <math.h>
     5 #include <stdio.h>
     6 #include <string.h>
     7 #include <iostream>
     8 #include <algorithm>
     9 using namespace std;
    10 
    11 int dp[1010][1010];
    12 
    13 int Max(int x, int y)
    14 {
    15     if(x >= y)
    16         return x;
    17     return y;
    18 }
    19 
    20 void run()
    21 {
    22     char s[1010];
    23     int i, j;
    24     while(gets(s))
    25     {
    26         memset(dp, 0, sizeof(dp));
    27         int len = strlen(s);
    28         for(i = 1; i <= len; i++)                  //记录路径,找到重复的字母
    29         {       
    30             for(j = 1; j <= len; j++)
    31             {
    32                 if(s[i-1] == s[len-j])
    33                     dp[i][j] = dp[i-1][j-1]+1;
    34                 else
    35                     dp[i][j] = Max(dp[i-1][j], dp[i][j-1]);                        
    36             }
    37         }
    38         printf("%d ", len-dp[len][len]);          //打印次数
    39         i = j = len; 
    40         while(i != 0 || j != 0)                           
    41         {
    42             if(s[i-1] == s[len-j] && i > 0 && j > 0)
    43             {
    44                 printf("%c", s[i-1]);
    45                 i--,j--;
    46             }
    47             else if(dp[i][j] == dp[i][j-1] && j > 0)
    48             {
    49                 printf("%c", s[len-j]);
    50                 j--;
    51             }
    52             else if(dp[i][j] == dp[i-1][j] && i > 0)
    53             {
    54                 printf("%c", s[i-1]);
    55                 i--;
    56             }
    57         }
    58         printf("
    ");
    59     }
    60 }
    61 
    62 int main(void)
    63 {
    64     run();
    65 
    66     return 0;
    67 }
    Make Palindrome

    找了另一种DP的方法:

    这里需要用到一个结论,即增加字符变为回文串与减少字符变为回文串的最小操作数是相同的,这里可以用手模拟几种情况,就可以得出这个结论。

    那么状态转移方程即为:

    d[i][j] = d[i+1][j-1]; str[i] == str[j]

    d[i][j] = min(d[i+1][j-1], d[i][j-1])+1; str[i] != str[j];

    如何去打印路径呢?我们知道LCS中是通过记录当前操作,然后通过递归的方式来打印路径的,这里也类似。

    由于回文串的特点是两边对称,所以,我们在把输入的字符串变为回文串的过程中可以通过左边的串来输出右边的串。

    这样递归的特点即是: printf("%c", str[i]); print_ans(i+1,j -1); printf("%c", str[i]);

    这样,即可保证字符串是左右对称的。

     1 #include <iostream>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <cstring>
     6 #include <string>
     7 #include <queue>
     8 using namespace std;
     9 
    10 const int MAXN = 1010;
    11 const int INF = 0x3f3f3f3f;
    12 
    13 int d[MAXN][MAXN];
    14 int path[MAXN][MAXN];
    15 bool vis[MAXN][MAXN];
    16 
    17 char str[MAXN];
    18 
    19 void init()
    20 {
    21     memset(path, -1, sizeof(path));
    22     memset(vis, 0, sizeof(vis));
    23 }
    24 
    25 int dp(int i, int j)
    26 {
    27     int &ans = d[i][j];
    28     if(i >= j) return 0;
    29     if(vis[i][j]) return ans;
    30     vis[i][j] = 1;
    31     if(str[i] == str[j]) { ans = dp(i+1, j-1); path[i][j] = 0;}
    32     else if(dp(i+1, j) < dp(i, j-1)) {ans = dp(i+1, j)+1; path[i][j] = 1;} // <=与 <的结果不同 
    33     else  { ans = dp(i,j-1)+1; path[i][j] = 2;} 
    34     return ans;
    35 }
    36 
    37 void print_ans(int i, int j)
    38 {
    39     if(i > j) return ;
    40     if(i == j) printf("%c", str[i]);
    41     if(path[i][j] == 0)
    42     {
    43         printf("%c", str[i]);
    44         print_ans(i+1, j-1);
    45         printf("%c", str[i]);
    46     }
    47     else if(path[i][j] == 1)
    48     {
    49         printf("%c", str[i]);
    50         print_ans(i+1, j);
    51         printf("%c", str[i]);
    52     }
    53     else if(path[i][j] == 2)
    54     {
    55         printf("%c", str[j]);
    56         print_ans(i, j-1);
    57         printf("%c", str[j]);
    58     }
    59 }
    60 
    61 void solve()
    62 {
    63     init();
    64     int n = strlen(str);
    65     int ans = dp(0, n-1);
    66     printf("%d ", ans);
    67     print_ans(0, n-1);
    68     printf("
    ");
    69 }
    70 
    71 int main()
    72 {
    73     while(~scanf("%s", str))
    74     {
    75         solve();
    76     }
    77     return 0;
    78 }
    Make Palindrome
  • 相关阅读:
    【C++】深度探索C++对象模型读书笔记--关于对象(Object Lessons)
    【操作系统】调度算法
    【vim】vim常用命令
    【linux】linux的数据流重定向
    以太网帧,IP,TCP,UDP首部结构
    IPv4编址及子网划分
    【计算机网络】计算机网络模型
    【计算机网络】NAT:网络地址转换
    【设计模式】C++中的单例模式
    (转)linux查找技巧: find grep xargs
  • 原文地址:https://www.cnblogs.com/Silence-AC/p/3394986.html
Copyright © 2011-2022 走看看