题目:http://poj.org/problem?id=1065
大意:
有N根木棍等待处理。机器在处理第一根木棍时需要准备1分钟,此后遇到长宽都不大于前一根木棍的木棍就不需要时间准备,反之则需要1分钟重新准备。比如木棍按照(3,3)、(1,3)、(1,4)、(2,3)的顺序进入,共需要准备3分钟
思路: 看数据,n<=5000, 长重都<=10000,是否需要重新准备依赖于长和重,但是假如将长和重都作为变量放入dp数组内,数组的大小将会达到10^8次方,再加上5000的n数据量,内存装不下,假如要对dp数组作遍历,即使是On的算法也会超时。
因此需要减少状态的量,顺着这个思路就想到了先预处理所有木棍。因为没有规定木棍需要按顺序放入,假如先将木棍按照长或者重升序排列,那么我们选择的时候就不需要再关注该变量了。
排序完之后题目就转化成了最长上升子序列的问题,也就是最少选择多少个上升子序列使得所有木棍都被选择完毕。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn1 = 5000 + 5;
const int maxn2 = 10000 + 5;
struct node {
int x, y;
}num[maxn1];
int len[maxn1];
bool cmp(node a, node b) {
if (a.x != b.x) return a.x < b.x;
else return a.y < b.y;
}
int main() {
int T; cin >> T;
while (T--) {
int n; cin >> n;
for (int i = 1; i <= n; i++) {
scanf("%d %d", &num[i].x, &num[i].y);
}
sort(num + 1, num + 1 + n, cmp);
int cnt=0,res=0;
while (cnt < n) {
res++;
memset(len, 0, sizeof(len));
int maxx = 0;
for (int i = 1; i <= n; i++) {
if (num[i].y==0) continue;
if (len[maxx] <= num[i].y) {
len[++maxx] = num[i].y;
cnt++;
num[i].y = 0;
}
else {
int flag = lower_bound(len, len + 1 + n, num[i].y) - len;
len[flag] = num[i].y;
}
}
}
cout << res << endl;
}
return 0;
}