紫书第九章-----动态规划初步(例题9-7 Partitioning by Palindromes UVA - 11584 、例题9-8 Color Length UVA - 1625 )

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccnuacmhdu/article/details/81430999

Partitioning by Palindromes UVA - 11584

/*
    状态:d[i]表示以1~i且以i结束的字符串的最少回文串数
    状态转移:d[i]=min{d[j-1]+1 | j<=i && s[j~i]是回文串},s[j~i]是回文串,那么更新d[j-1]+1=d[i]
*/

#include<iostream>
#include<cstring>
using namespace std;

const int maxn=1005;

int n;
char s[maxn];
int d[maxn];

bool is_palindrom(int l,int r){
    int i=l,j=r;
    while(i<=j){
        if(s[i]!=s[j]) return false;
        i++;
        j--;
    }
    return true;
}

int main()
{
    cin>>n;
    while(n--){
        cin>>(s+1);
        int len=strlen(s+1);
        for(int i=0;i<=len;i++) d[i]=i;
        for(int i=1;i<=len;i++){
            for(int j=1;j<=i;j++){
                if(is_palindrom(j,i)) d[i]=min(d[i],d[j-1]+1);
            }
        }
        cout<<d[len]<<endl;
    }
    return 0;
}

Color Length UVA - 1625

【题目大意】
参考原题及《算法竞赛入门经典(第2版)》
【题目分析】
本题容易找到状态,也容易得到状态转移方程,难点在于怎么计算状态转移方程中的增量cnt,以及容易犯错的边界处理。本题技巧性较强,不易掌握。

/*
下面解法是在刘汝佳《算法竞赛入门经典呢(第2版)》相关讲解的基础上进行!

    状态:d[i][j]表示字符串s1的前i个和字符串s2的前j个形成的最优解
        cnt[i][j]表示因为使用s1[i],s2[j]造成了增量
    状态转移:d[i][j]=min{d[i-1][j]+cnt[i-1][j],d[i][j-1]+cnt[i][j-1]}
*/

#include<iostream>
#include<cstring>
using namespace std;

const int maxn=5005;
const int INF=(1<<30);

int n;
char s[3][maxn];
int dp[maxn][maxn];
int be[3][30];
int en[3][30];

int main()
{
    cin>>n;
    while(n--){
        cin>>(s[1]+1);
        cin>>(s[2]+1);
        int len1=strlen(s[1]+1);
        int len2=strlen(s[2]+1);
        //注意初始化成一个maxn,要注意初始化的是26个字母的开始和结束位置,不是字符串中每个字符!!
        for(int i=1;i<=2;i++){
            for(int j=1;j<=26;j++){
                be[i][j]=maxn;
            }
        }
        memset(en,0,sizeof(en));
        for(int i=1;i<=2;i++){
            for(int j=1;j<=strlen(s[i]+1);j++){
                if(be[i][s[i][j]-'A'+1]==maxn) be[i][s[i][j]-'A'+1]=j;
                en[i][s[i][j]-'A'+1]=j;
            }
        }
/*
        for(int i=1;i<=26;i++){
            cout<<be[1][i]<<" "<<en[1][i]<<" and "<<be[2][i]<<" "<<en[2][i]<<endl;
        }
*/
        for(int i=0;i<=len1;i++){
            for(int j=0;j<=len2;j++){
                int cnt=0,res=INF;
                for(int k=1;k<=26;k++){
                        //如果把be,en初始化为0,会导致这里的判断错误,下面判断的是任意个字母,如果在上下开始,
                        //上下还有尚未结束的!一旦初始化为0,那么比如当i=0的时候,任意字母都默认上面已经开始了,
                        //举个例子:题目中的样例1的D字母当i=0时候的情况
                    if((be[1][k]<=i || be[2][k]<=j) && (en[1][k]>i || en[2][k]>j)) cnt++;
                }
                if(i) res=min(dp[i-1][j],res);
                if(j) res=min(dp[i][j-1],res);
                dp[i][j]=cnt+(res==INF?0:res);
            }

        }
        cout<<dp[len1][len2]<<endl;

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ccnuacmhdu/article/details/81430999