【新手记录】
// 2016-5-4 16:30:29
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4268
/*
贪心法
题目:
用A的矩阵去覆盖B的矩阵,矩阵有height,weight
矩阵不能旋转,
每个矩阵只能用一次,
问最多能用A覆盖B几个
A:o o o o o
B:* * * * *
思路:
覆盖也就是保证A.h>= B.h && A.w >= B.w
分两步去满足条件,1#满足h, 2#满足w
1#对A,B的矩阵按h从小到大排序,h相同的按w从小到大排序
2#
1> 对Ai矩阵找出所有的Bj矩阵满足, Ai.h>= Bj.h, 构成集合set, 然后选取Ai去覆盖Bj.w最大的Bj
2> 因为Ai+1.h >= Ai.h, 所以Ai+1.h >= 之前的Bj.h, 继续添加新的Bj进set里,继续选择Ai+1去覆盖Bj.w最大的Bj,
3> 迭代即可
关键点
1#找出Ai.h >= Bj.h 的Bj
2#Ai.h >= Bj.h 则 Ai+1.h >= Bj.h
总结:
T<=40, N<=10^5,
即使O(n^2)复杂度, 10^10也超时间了。
A: o o o o o
B: * * * * *
B的全排列种可能,然后A去覆盖B,看能覆盖几个,O(n!),则应该考虑是动态规划问题
又即使O(n^2)复杂度, 10^10也超时间了,故考虑是贪心问题。
实现:
O(n^2)
1》遍历Bi,去找最小的Aj,Aj能覆盖Bi,
O(n)
2》遍历Ai, 去找最大的Bi, 利用
1#找出Ai.h >= Bj.h 的Bj
2#Ai.h >= Bj.h 则 Ai+1.h >= Bj.h
时间复杂度分析:
N = 10 ^5,
O(n^2)都TLE了,只能O(nlgn),O(n)这种级别
用到:
multiset,集合的用法
*/
// 2016-5-4 15:02:04 #include<stdio.h> #include<set> #include<algorithm> using namespace std; struct Node { int h; int w; }; bool cmp(const Node n1, const Node n2) { if (n1.h != n2.h) { return n1.h < n2.h; } else { return n1.w < n2.w; } } Node aNode[100001]; Node bNode[100001]; multiset<int> mySet; multiset<int>::iterator it; int main() { int t, n; int i, j; scanf("%d", &t); while (t--) { scanf("%d", &n); for (i = 0; i < 2 * n; i++) { int h, w; scanf("%d", &h); scanf("%d", &w); if (i < n) { aNode[i].h = h; aNode[i].w = w; } else { bNode[i - n].h = h; bNode[i - n].w = w; } } sort(aNode, aNode + n, cmp); sort(bNode, bNode + n, cmp); int ans = 0; j = 0; mySet.clear(); for (i = 0; i < n; i++) { while (j < n && aNode[i].h >= bNode[j].h) { mySet.insert(bNode[j].w); j++; } if (mySet.empty()) continue; it = mySet.upper_bound(aNode[i].w); if (it != mySet.begin()) it--; if (*it <= aNode[i].w) { mySet.erase(it); ans++; } } printf("%d\n", ans); } return 0; }