POJ 1065 & 3636的区别
两个题目看起来没什么区别,都是嵌套,唯一的不同就是一个要求l <= l' and w <= w'. 而另一个则要求w1 < w2 and h1 < h2.多了一个等于号。1065在很久以前就被我水过了。搜了一下解题报告都是有关偏序集的。抑或是跟最长上升子序列有关。其实以我自己的想法完全可以模拟accepted掉,当然代价就是时间效率可能没有那么好。最坏情况下是n^2级,在3636大概是花了800ms过了。
首先是1065,想法很简单,就是先二级排序,如果l相等就对w排序,都是升序排列。然后设置一个标记访问变量。从第一个开始遍历,如果这个位置还没有访问,就在后面没有访问的位置里面找l和w都比当前大的,标记为已访问,更新l和w的最小值。代码更容易看懂:
#include<iostream> #include<algorithm> using namespace std; struct arra{ int a, b; }; arra num[5000]; int cmp(const void *a,const void *b) { struct arra *c=(struct arra*)a; struct arra *d=(struct arra*)b; if (c->a == d->a) return c->b - d->b; return c->a - d->a; } int main() { int tot; int i, j, k; int a; int c; int mina; int minb; int vi[5000]; scanf("%d", &tot); for (i = 0; i < tot; i++) { scanf("%d", &a); memset(vi, 0, sizeof(vi)); c = 0; for (j = 0; j < a; j++) scanf("%d%d", &num[j].a, &num[j].b); qsort(num, a ,sizeof(num[0]), cmp); for (j = 0; j < a; j++) { if (!vi[j]) { minb = num[j].b; c++; for (k = j + 1; k < a; k++) { if (!vi[k] && num[k].b >= minb) { vi[k] = 1; minb = num[k].b; } } } } printf("%d\n", c); } return 0; }
至于3636则有了一点小小的变化,多了一个等于。其实还是可以用原来的方法求,只是需要变两个地方。
首先就是排序上,不能再用原来的方法排序。因为如果w相等的时候是应该先处理h大的,为什呢。设w1==w2,h1<h2。假设先处理小的,如果后面出现了w3>w1,h3>h2时,先嵌入了(w1,h1),再出现w4>w3,h4<=h2时就多出了一个。比如网上出现的一个样例:
5
1 8 2 4 2 3 3 5 4 4
这个例子非常便于理解。所以排序应该改成:
bool cmp(arra a, arra b){ if (a.a == b.a) return a.b > b.b; return a.a < b.a; }
另外还有一个地方就是内层循环时判断条件应该变成:
if (!vi[k] && (num[k].a > mina && num[k].b > minb)){ vi[k] = 1; minb = num[k].b; mina = num[k].a; }
3636代码如下:
#include <stdio.h> #include <string.h> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; struct arra{ int a, b; }; arra num[20005]; bool cmp(arra a, arra b){ if (a.a == b.a) return a.b > b.b; return a.a < b.a; } int main() { int tot; int i, j, k; int a; int c; int mina; int minb; int vi[20005]; scanf("%d", &tot); for (i = 0; i < tot; i++) { scanf("%d", &a); memset(vi, 0, sizeof(vi)); c = 0; for (j = 0; j < a; j++) scanf("%d%d", &num[j].a, &num[j].b); sort(num, num + a , cmp); for (j = 0; j < a; j++) { if (!vi[j]) { minb = num[j].b; mina = num[j].a; c++; for (k = j + 1; k < a; k++) { if (!vi[k] && (num[k].a > mina && num[k].b > minb)) { vi[k] = 1; minb = num[k].b; mina = num[k].a; } } } } printf("%d\n", c); } return 0; }