一道有意思的思维题2 --- 排序、枚举
这道题是又一次在和学弟吃饭的路上听学弟讲的,感觉挺不错的^_^,这样仿佛经常听学弟讲题能收获不少呀,可能明年笔试有望了,哈哈~
Problem:
平面上给了有n个人,位置由(x,y)元组给定,平面上还有m扇门,位置由(x,y)给定。现在约定每扇门只能进一个人,且人只能向左和下移动(向x-1和y-1移动),请问最多有多少人进门?
Solution:
将人和门按x值从大到小排序,枚举门。对于当前枚举的门i,将值大于door[i].x的所有人的y值放入set中,找到大于等于door[i].y的最小值,将其分配给门i,然后从set中剔除,接着枚举门i+1。
代码如下:
#include <iostream> #include <algorithm> #include <set> using namespace std; /* Problem: 平面上给了有n个人,位置由(x,y)元组给定,平面上还有m扇门,位置由(x,y)给定。现在约定每扇门只能进一个人,且人只能向左和下移动(向x-1和y-1移动),请问最多 有多少人进门? Solution: 将人和门按x值从大到小排序,枚举门。对于当前枚举的门i,将值大于door[i].x的所有人的y值放入set中,找到大于等于door[i].y的最小值,将其分配给门i,然后从set 中剔除,接着枚举门i+1。 */ const int N = 1e3 + 5; typedef pair<int, int> Tuple; bool cmp(const Tuple a, const Tuple b) { return a.first > b.first; } multiset<int> s; multiset<int>::iterator it; int main() { int n, m; cin >> n >> m; Tuple people[N], door[N]; for (int i = 0; i < n; i++) { cin >> people[i].first >> people[i].second; } sort(people, people + n, cmp); for (int i = 0; i < m; i++) { cin >> door[i].first >> door[i].second; } sort(door, door + m, cmp); int ans = 0; int k = 0; for (int i = 0; i < m; i++) { while (k < n) { if (people[k].first >= door[i].first) { s.insert(people[k].second); k++; } } if (s.count(door[i].second) > 0) { ans++; s.erase(s.find(door[i].second)); } else { it = s.upper_bound(door[i].second); if (it != s.end()) { ans++; s.erase(it); } } } std::cout << "Answer = " << ans << endl; return 0; } /* 2 2 5 3 6 5 3 4 4 2 */