一道有意思的思维题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
*/

 

posted @ 2019-09-30 19:57  茶飘香~  阅读(213)  评论(0编辑  收藏  举报