DP1练习-5.14日

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

今天做了两个DP的题目,只要掌握了方法,基本上都是水题。下面简单说一下:传送门(点击打开链接

A - Prince and Princess

思路:

求最长公共子序列,只不过数据较大,不能直接求,而是将LCS问题进行转换为LIS问题,求最长上升子序列即可。

如何转化?:

最长公共子序列向最长递增子序列退化:


  设有序列A,B。记序列A中各个元素在B 中的位子(降序排列),然后按在A中的位置依次列出按后求A的最长递增子序列。


  例如:有A={a,b,a,c,x},B={b,a,a,b,c,a}则有a={6,3,2},b={4,1},c={5};x=/;(注意降序排列)


然后按A中次序排出{a(6,3,2),b(4,1),a(6,3,2),c(5),x()}={6,3,2,4,1,6,3,2,5};对此序列求最长递增子序列即可(转自:点击打开链接

代码:

#include <bits/stdc++.h>
using namespace std;
const int M = 100000;

int n,p,q;

int len;

int low[M],a[M],b[M],num[M];

int main()
{
    int t;
    int cas = 1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&n,&p,&q);
        memset(num,-1,sizeof(num));
        for(int i=0;i<=p;i++)
        {
            scanf("%d",&a[i]);
            num[a[i]] = i;  //LCS转换为LIS所用记录位置的数组
        }
        int cnt = 0;
        int m;
        for(int i=0;i<=q;i++)
        {
            scanf("%d",&m);
            if(num[m]!=-1)
            {
                b[cnt++]=num[m];  //处理之后,直接求b的最长上升子序列即可
            }
        }
        len = 0;  //下面是二分找最长上升子序列
        memset(low,0,sizeof(low));
        low[0] = b[0];
        for(int i=1;i<cnt;i++)
        {
            if(b[i]>low[len])
            {
                low[++len] = b[i];
            }
            else
            {
                int p = lower_bound(low,low+len,b[i])-low;

                low[p] = b[i];
            }
        }
        printf("Case %d: %d\n",cas,len+1);
        cas++;
    }
    return 0;
}

E - Partitioning by Palindromes

题意:给你一个串进行划分,问最少可以分成几个回文串。

思路:

暴力枚举每一部分,然后进行比较,取最小的,详见代码:

#include <bits/stdc++.h>
using namespace std;
int dp[1005];
char s[1005];
int main()
{
    int t;
    int flag;
    scanf("%d",&t);
    while(t--)
    {
        cin>>s;
        int len = strlen(s);
        memset(dp,0x3f,sizeof(dp));
        dp[0] = 1;
        for(int i=1; i<=len-1; i++)   //以i为结尾
        {
            for(int j=0;j<=i;j++)  //以j为起点的
            {
                 flag = 1;
                 for(int k=0;k<=(i-j)/2;k++) //每一段区间是否形成回文串
                 {
                     if(s[i-k]!=s[j+k])
                     {
                         flag = 0;
                         break;
                     }
                 }
                if( flag == 1) //若形成了,在j的基础上加一操作
                {
                   if(dp[ i ] > dp [ j - 1] + 1)
                   {
                        dp[ i ] = dp[ j - 1 ] + 1; //找最小
                   }
                }
            }
        }
        printf("%d\n" , dp[len-1]);
    }
    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页