1. 程式人生 > >PAT 1045. Favorite Color Stripe (30)(按一定順序找出最長的子序列,動態規劃)

PAT 1045. Favorite Color Stripe (30)(按一定順序找出最長的子序列,動態規劃)

官網

1045. Favorite Color Stripe (30)

Eva is trying to make her own color stripe out of a given one. She would like to keep only her favorite colors in her favorite order by cutting off those unwanted pieces and sewing the remaining parts together to form her favorite color stripe.
It is said that a normal human eye can distinguish about less than 200 different colors, so Eva’s favorite colors are limited. However the original stripe could be very long, and Eva would like to have the remaining favorite stripe with the maximum length. So she needs your help to find her the best result.
Note that the solution might not be unique, but you only have to tell her the maximum length. For example, given a stripe of colors {2 2 4 1 5 5 6 3 1 1 5 6}. If Eva’s favorite colors are given in her favorite order as {2 3 1 5 6}, then she has 4 possible best solutions {2 2 1 1 1 5 6}, {2 2 1 5 5 5 6}, {2 2 1 5 5 6 6}, and {2 2 3 1 1 5 6}.

輸入描述:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=200) which is the total number of colors involved (and hence the colors are numbered from 1 to N). Then the next line starts with a positive integer M (<=200) followed by M Eva’s favorite color numbers given in her favorite order. Finally the third line starts with a positive integer L (<=10000) which is the length of the given stripe, followed by L colors on the stripe. All the numbers in a line are separated by a space.

輸出描述:
For each test case, simply print in a line the maximum length of Eva’s favorite stripe.

輸入例子:
6
5 2 3 1 5 6
12 2 2 4 1 5 5 6 3 1 1 5 6

輸出例子:
7

題目大意

  • 1.給出一個順序,要你在第二行的數列中選出與這個順序相同的最長的子序列,只要按上述順序就行,可以不要其中的一項。

解題思路

  • 1.想了好久真的都想不到要用動態規劃畫一個表出來,其中like為行,表示題目中的喜歡的序列,s為原來的絲帶的顏色序列。表p如下:
LIKE\S 2 2 4 1 5 5 6 3 1 1 5 6
2 1 2 2 2 2 2 2 2 2 2 2 2
23 1 2 2 2 2 2 2 3 3 3 3 3
231 1 2 2 3 3 3 3 3 4 5 5 5
2315 1 2 2 3 4 5 5 5 5 5 5 6
23156 1 2 2 3 4 5 6 6 6 6 6 7
  • 2.對比第二行23和第一行2的區別,可以發現,假如沒有3,那麼第二排就跟第一排是一樣的,來了個三有了什麼區別呢?來了個3,且如果s[j]==like[i]的話(即s數列後面遇到了一個三)則意味著要在前一行的同一列的基礎上加一,否則不變,數學語言為:if(s[j]==like[i]){p[i][j]=p[i-1][j]+1},如表中加粗的3,則為第二行與第一行的區別所在。同時,後面如果繼續還來3的話還要在同一行前面一個數的基礎上加一,再與前面的如果一直沒遇到3就與前一行一致,聯合起來就變為取p[i-1][j],p[i][j]的最大值。即:else{s[i][j]=max(s[i][j-1],s[i-1][j])}
  • 3.都知道動態規劃是要找一個表,想不到是要找這樣子的表。

程式碼提示

  • 1.我是先將第一行搞定,然後把第一列搞定,然後再根據這倆個為基礎吧上述表填完的。
  • 2.不知道為什麼要構建這個表的話去看我的這篇部落格簡談動態規劃

程式碼

#include<iostream>
#include<vector>
#include<string>
#include<iomanip>
#include<sstream>
#include<algorithm>
using namespace std;
int p[10005][205];

int main()
{
    int n; cin >> n;
    int m;
    cin >> m;
    vector<int> like(m);
    for (int i = 0; i < m; i++)
    {
        cin >> like[i];
    }
    int l; cin >> l; vector<int> s(l);
    int num = 0;
    for (int i = 0; i < l; i++)
    {
        cin >> s[i];
        //填好第一行
        if (s[i]==like[0])
        {
            num++;
        }
        p[0][i] = num;
    }
    for (int i = 1; i < m; i++)
    {
        for (int j = 0; j < l; j++)
        {
        //填第一列
            if (j==0)
            {
                if (like[i] == s[0])
                {
                    p[i][0] = p[i - 1][0] + 1;
                }
                else
                    p[i][0] = p[i - 1][0];
            }
            else
            {
            //根據第一行和第一列吧剩下的填完
                if (s[j] == like[i])
                {
                    p[i][j] = p[i][j - 1] + 1;
                }
                else
                {
                    p[i][j] = max(p[i][j - 1], p[i - 1][j]);
                }
            }
        }
    }
    cout << p[m - 1][l - 1] << endl;
    return 0;
}