Description
(a) The setup time for the first wooden stick is 1 minute.
(b) Right after processing a stick of length l and weight w , the machine will need no setup time for a stick of length l' and weight w' if l <= l' and w <= w'. Otherwise, it will need 1 minute for setup.
You are to find the minimum setup time to process a given pile of n wooden sticks. For example, if you have five sticks whose pairs of length and weight are ( 9 , 4 ) , ( 2 , 5 ) , ( 1 , 2 ) , ( 5 , 3 ) , and ( 4 , 1 ) , then the minimum setup time should be 2 minutes since there is a sequence of pairs ( 4 , 1 ) , ( 5 , 3 ) , ( 9 , 4 ) , ( 1 , 2 ) , ( 2 , 5 ) .
Input
Output
Sample Input
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
Sample Output
2 13
书上说这是一道要稍加思索的题目,使得我高估了它,其实并没有那么难。
思路:
易知根据要求得到的是一个有向无环图,既然如此,很容易想到只要从起点每次都找到尾(满足条件的递增),找的次数就是答案。
这是O(N^2)解法:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int N = 5000 + 5; struct Stick { int l, w; } ele[N]; bool vis[N]; inline bool cmp(const Stick a, const Stick b){ if(a.w == b.w) return a.l < b.l; return a.w < b.w; } int solve(const int n) { int cnt = 0, res = 0; sort(ele + 1, ele + n + 1, cmp); memset(vis, false, sizeof(vis)); while(cnt != n) { int w = 0, l = 0; for(int i = 1; i <= n; i++) { if(vis[i]) continue; if(w <= ele[i].w && l <= ele[i].l) { vis[i] = true; cnt++; w = ele[i].w; l = ele[i].l; } } res++; } return res; } int main() { int T; scanf("%d", &T); while( T-- ) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d%d", &(ele[i].l), &(ele[i].w)); printf("%d\n", solve(n)); } return 0; }
再经过转变可以看出答案应该是最长非递增(这里的递增理解为w[i] <= w[j] && l[i] <= l[j] && i < j)子序列(LDS)的长度,如:
ooooooooo...(第一条递增序列)
ooooo...(第二条递增序列)
..
..
ooo(第res条递增序列)(res是答案)
那么LDS的长度一定是res,应为其中一条LDS是每条递增序列的首个元素组成。
由此可以用经过优化的LDS计算,复杂度为O(N*logN):
代码来自:http://www.hankcs.com/program/cpp/poj-1065-wooden-sticks.html
- #include <iostream>
- #include <algorithm>
- #include <functional>
- using namespace std;
- pair<int, int> stick[5000 + 16];
- int dp[5000 + 16]; // dp[i] := 长度为i+1的下降子序列中末尾元素的最大值
- ///SubMain//
- int main(int argc, char *argv[])
- {
- #ifndef ONLINE_JUDGE
- freopen("in.txt", "r", stdin);
- freopen("out.txt", "w", stdout);
- #endif
- int T;
- cin >> T;
- while (T--)
- {
- int n;
- cin >> n;
- for (int i = 0; i < n; ++i)
- {
- cin >> stick[i].first >> stick[i].second;
- }
- sort(stick, stick + n);
- memset(dp, -1, n * sizeof(int));
- for (int i = 0; i < n; ++i)
- {
- *lower_bound(dp, dp + n, stick[i].second, greater<int>()) = stick[i].second;
- }
- cout << lower_bound(dp, dp + n, -1, greater<int>()) - dp << endl;
- }
- #ifndef ONLINE_JUDGE
- fclose(stdin);
- fclose(stdout);
- system("out.txt");
- #endif
- return 0;
- }