1. 程式人生 > 實用技巧 >PAT 1045 Favorite Color Stripe (30分) 動態規劃

PAT 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}.

Input Specification:
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 (≤104

​​ ) which is the length of the given stripe, followed by L colors on the stripe. All the numbers in a line a separated by a space.

Output Specification:
For each test case, simply print in a line the maximum length of Eva's favorite stripe.

Sample Input:

6
5 2 3 1 5 6
12 2 2 4 1 5 5 6 3 1 1 5 6

Sample Output:

7

解析

題目大意:

Eva試著從給出的布條中選出她自己的彩色布條。她想要僅僅保留按照她最喜歡的順序排列的她喜歡的顏色,並且剪掉那些不喜歡的部分再將剩下的部分縫在一起來組成她最喜歡的彩色布條。所以她需要你的幫助來找出最好的結果。

注意結果可能不唯一,但是你只需要告訴她最大的長度。舉個例子,給你一個 {2 2 4 1 5 5 6 3 1 1 5 6}.的彩色布條。如果Eva最喜歡的順序排列的最喜歡的顏色為{2 3 1 5 6},這樣按照她最喜歡的顏色的順序去選取,她有4種可能的最佳方案 {2 2 1 1 1 5 6}, {2 2 1 5 5 5 6}, {2 2 1 5 5 6 6}, 和{2 2 3 1 1 5 6}。(注意最喜歡的順序排列 的每個數字都不重複)

解題報告:

  • 因為最喜歡的順序排列的每個數字都不重複,也就是說我可以給這些數字重新定序(注意這個轉換思路非常巧妙)book[i] = j表示在最喜歡的顏色排列中,顏色i的下標為j
  • 先在輸入的時候剔除不在喜歡的序列中的元素(假如輸入的是顏色k,查一下book[k]是否有效),然後我們直接在當前位置不儲存顏色k,而是儲存book[k],這樣原輸入陣列每個位置代表的含義(本來是顏色i)就變成了顏色i在最喜歡的顏色中的下標。
  • 這樣我們從中選取滿足最喜歡順序的片段,就轉化為一個LIS(最長遞增子序列)問題了,也就是從中找出最長的非遞減子序列的長度,這樣我們就可以用動態規劃了(關於這個解法,推薦一篇部落格,講的非常清楚)。

程式碼

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


int main() {
    int n, m, x, l, num = 0, maxn = 0;
    // 原顏色條紋
    int stripe[10001];
    // 每個顏色在最喜歡顏色序列中的位置(唯一)
    int book[201];

    cin >> n >> m;
    // 初始化
    fill(book, book + 201, -1);

    // 輸入最喜歡的顏色序列
    for (int i = 1; i <= m; ++i) {
        cin >> x;
        // 轉成book[顏色]=下標
        book[x] = i;
    }
    // 輸入l個條紋顏色
    cin >> l;
    for (int i = 1; i <= l; ++i) {
        cin >> x;
        // 取出無效的(不喜歡的部分)
        if (book[x] != -1) {
            // 把顏色轉成當前顏色在最喜歡顏色中的位置
            stripe[++num] = book[x];
        }
    }
    // 動態規劃求解最長連續遞增序列
    // dp[i]表示從開始位置到當前位置的最長遞增子序列的長度
    int dp[num + 1];
    for (int i = 1; i <= num; ++i) {
        // 從每個位置開始,最短序列長度是1(自身)
        dp[i] = 1;
        // 狀態轉移
        for (int j = 1; j < i; ++j) {
            if (stripe[j] <= stripe[i]) dp[i] = max(dp[i], dp[j] + 1);
        }
        // 儲存其中最大的長度
        maxn = max(maxn, dp[i]);
    }

    // 輸出最大值
    cout << maxn;

    return 0;
}