ZOJ1025-Wooden Sticks 加工木棒問題
【問題描述】
現有n根木棒,已知它們的長度和重量。要用一部木工機一根一根地加工這些木棒。該機器在加工過程中需要一定的准備時間用於清洗機器、調整工具和模板。
木工機需要的准備時間如下:
(1) 第一根木棒需要1min的准備時間;
(2) 在加工了一根長為l,重為w的木棒后,接着加工一根長為l’(l≤l’),
重為w’(w≤w’)的木棒是不需要任何准備時間的,否則需要1min的准備時間。
給定n根木棒,你要找到最少的准備時間。例如現在有長度和重量分別為(4,9)、(5,2)、(2,1)、(3,5)和(1,4)的5根木棒,那么所需准備時間最少為2min,順序為(1,4)-》(3,5)-》(4,9)-》(2,1)-》(5,2)。
【輸入】
輸入有多組測試例。輸入數據的第一行是測試例的個數T。
每個測試例兩行:
第一行是一個整數n(1≤n≤5000),表示有多少根木棒;
第二行包括n×2個整數,表示l1,w1,l2,w2,l3,w3,…,ln,wn,全部不大於10000,其中li和wi表示第i根木棒的長度和重量。
數據由一個或多個空格分隔。
【輸出】
輸出是以分鍾為單位的最少准備時間,一行對應一個測試例。
【輸入樣例】
3
5
4 9 5 2 2 1 3 5 1 4
3
2 2 1 1 2 2
3
1 3 2 2 3 1
【輸出樣例】
2
1
3
思路:
拿分析的樣例來看,直接想到了離散上的偏序集,但只是想到了,不知道該怎么解。。。
看了下題解有了思路。先通過一輪cmp構造的排序,將問題進行轉化——按照每個棒子的長度從小到大進行排序,然后得到基於棒子長度從小到大排序的棒子重量數組,將這個數組提取到w中保存,或者你不提出來也行,我就是為了方便,我稱之為空間換簡潔。
然后我們在把2維的偏序關系降到1維后(對,這個題就是降維打擊:),就發現現在問題已經轉換成了求w數組的最長上升子序列的最小個數,而這個問題,可以再次轉換成求w數組的最長遞減子序列的長度。后者的轉換很容易理解,比如這個數組w的最長遞減子序列的長度為5,那這5個值肯定各自在一個獨立的最長上升子序列中。
兩行大概就把問題的核心說清了,然后coding
#include <iostream> #include <cstring> #include <algorithm> #define N 5007 using namespace std; int n,T; struct stick{ int l,w; } sticks[N]; int w[N]; int dp[N]; bool cmp(stick a,stick b) { if(a.l == b.l) return a.w < b.w; else if(a.l < b.l) return true; return false; } int LIS(int* w) { int j;//j為當前最大結束點的坐標 dp[j=1] = w[1]; for(int i = 2;i <= n;i++) { if(w[i] < dp[j]) dp[++j] = w[i]; else if(w[i] == dp[j]) continue; else { for(int k = j;k >= 1;k--) { if(k == 1) dp[1] = w[i]>dp[1]?w[i]:dp[1]; //找到所有“合適”的位置 if(w[i]>dp[k] && w[i]<dp[k-1]) dp[k] = w[i]; } } } return j; } int main() { cin>>T; while(T--) { cin>>n; int ans = 0; for(int i = 1;i <= n;i++) cin>>sticks[i].l>>sticks[i].w; sort(sticks+1,sticks+1+n,cmp); for(int i = 1;i <= n;i++) w[i] = sticks[i].w; cout<<LIS(w)<<endl; } return 0; }