DP1練習-5.14日

今天做了兩個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;
}
發佈了642 篇原創文章 · 獲贊 279 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章