题意:有一些木棍,每个有长度和重量,要求把这些木棍排成若干两个属性值均不下降的序列。问至少要分为多少个序列。
分析:如果木棍a可以接在木棍b的前面(a的两个属性值均不大于b),那么我们由a向b连一条边。但如果存在a->b,b->c,则我们不连接a,c。这样我们就得到了一个图,根据建图方法可知这个图一定是无环的。现在我们把问题转化为求这个图的最小路径覆盖。但是由于它是无环的当我们走到一个岔口,无论选择那条路都无所谓,因为剩下的一条路早晚要走,现在走和以后走都一样。我们只需要保证我们所构成的任何一个序列的中间不能插入木棍即可。具体做法是将所有木棍排序,先按一个属性,一个属性相等的按第二个属性进行不降排序。如此,我们每次从左到右找到一个不降序列,直到所有木棍都被找出即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; #define maxn 5005 struct Stick { int weight, length; } stick[maxn]; int n; bool vis[maxn]; bool operator <(const Stick &a, const Stick &b) { return a.length < b.length || (a.length == b.length && a.weight < b.weight); } void input() { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d%d", &stick[i].length, &stick[i].weight); } int work() { memset(vis, 0, sizeof(vis)); int ret = 0; for (int i = 0; i < n; i++) { if (vis[i]) continue; int p = stick[i].weight; ret++; for (int j = i + 1; j < n; j++) if (!vis[j] && stick[j].weight >= p) { p = stick[j].weight; vis[j] = true; } } return ret; } int main() { //freopen("t.txt", "r", stdin); int t; scanf("%d", &t); while (t--) { input(); sort(stick, stick + n); printf("%d\n", work()); } return 0; }