目錄
1,題目描述
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,3,1,5,6},表示顏色2在第一位,顏色3要在2後面,顏色1要在3後面……以此類推(不必所有喜歡的顏色全部出現,剛開始一直在糾結這裏)。
這裏有一個色帶,它的顏色順序是這樣的{2 2 4 1 5 5 6 3 1 1 5 6},現在需要計算(Eva would like to have the remaining favorite stripe with the maximum length.),按照Eva喜歡的顏色順序,最長可以拼成多長的色帶(原色帶的順序保持不變)。本例中最優解有以下幾種:{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}.
輸入
- 第一行: 樣例中涉及到的顏色數目N;
- 第二行:Eva喜歡的顏色數目M,M種顏色的編號及順序;
- 第三行:綵帶長度L,依次對應的顏色種類及順序;
輸出
- 滿足Eva喜好的顏色及順序的最大長度;
說明
- Eva可以辨別的顏色數目不超過200;
- 顏色編號1-N;
2,思路
這一題參考了柳神的思路,瞭解到這其實是一個LIS(Longest Increasing Sequence,最長不下降子序列)的一個變化(Eva喜歡的顏色中,排最前的賦值最小,越往後越大。並將新設定的值替換掉原先色帶的顏色編號)。於是乎,轉戰晴神筆記,瞭解一下LIS問題。
核心思想
- 重新聲明一個數組num,將Eva喜歡的顏色編號,按照先後順序重新賦值,比如{2 3 1 5 6},num[2]=1,num[3]=2,num[1]=3……
- 在接受原色帶時,剔除Eva不喜歡的顏色,並將喜歡的顏色重新編號:
- 此時問題便轉換爲LIS問題,並可用動態規劃求解。時間複雜度O(n^2);
LIS問題
以下圖片內容均來自《算法筆記》——胡凡(又稱“晴神筆記”)
1,問題的定義及複雜之處
2, 動態規劃求解問題
3,舉例
4,示例代碼
3,代碼
#include<iostream>
#include<vector>
#include<climits>
using namespace std;
int main(){
//#ifdef ONLINE_JUDGE
//#else
// freopen("1.txt", "r", stdin);
//#endif
int num[201], data[10000];
int n, m, l; //n涉及到的顏色數 mEva喜歡的顏色數目 l原色帶的長度
int id, index = 0;
cin>>n>>m;
for(int i = 1; i <= m; i++){
scanf("%d", &id);
num[id] = i; //爲顏色出現的先後順序編號
}
cin>>l;
for(int i = 0; i < l; i++){
scanf("%d", &id);
if(num[id] > 0){ //只保留Eva喜歡的顏色
data[index++] = num[id];
}
}
int dp[10000], maxLen = 0;
for(int i = 0; i < index; i++){ //原色帶處理完之後 長度爲index
dp[i] = 1;
for(int j = i - 1; j >= 0; j--){
if(data[i] >= data[j])
dp[i] = max(dp[i], dp[j]+1);//動態方程
}
maxLen = max(maxLen, dp[i]); //記錄最大值
}
cout<<maxLen;
return 0;
}