小球投盒子C++实现

题目描述:

小红一共有 n 个盒子,标号为 1 到 n,小红向盒子里放入小球 m 次,每次进行以下两个操作中的一个:

  1. 向编号为 x 的盒子里放入一个小球;
  2. 向除了编号为 x 的其他 n−1 盒子里放入一个小球。
    小红想知道,第几次操作之后,所有盒子里至少都有一个小球,如果一直无法达到这个目标,输出 −1。

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 256M,其他语言512M

输入描述:

第一行两个整数 n 和 m,表示盒子的数量和操作的次数。
接下来 m 行,每行两个整数 t_i 和 x_i,表示第 i 次操作的类型和 x 的值。
1 <= n, m <= 10^5
1 <= t_i <= 2
1<= x_i <= n

输出描述:

输出一个整数,表示第几次操作之后,所有盒子里至少都有一个小球,如果一直无法达到这个目标,输出 -1。

示例1:

输入例子:
3 3
1 1
1 2
1 3
输出例子:
3
例子说明:
三次操作之后,所有盒子里都至少有一个小球。

示例2:

输入例子:
3 4
1 1
2 2
1 3
1 2
输出例子:
4
例子说明:
第一次操作后,盒子 1 里有小球。
第二次操作后,盒子 1、3、4 里有小球。
第三次操作后,盒子 1、3、4 里有小球。
第四次操作后,每个盒子里都有小球。

解题思路:

使用两个unordered_set <int> op1, op2;
t_i代表第i次操作的类型,总共就有两个类型 1 和 2;
如果是类型1,那就把盒子编号x放入op1里,表示编号为x的盒子中已经放了小球了;
如果是类型2,那就把盒子编号x放入op2里,表示在除了编号为x的盒子中都放了小球了;

更具体一些:
如果是第1种类型,t = 1,它代表向编号为 x 的盒子里放入一个小球,那么把x插入到op1里面,表明编号为x的盒子中已经有小球了。
这个时候我们要检查op1的大小是否为盒子总数n,如果是n那么就代表所有的盒子已经满了。因为unordered_set 里面是不允许有重复元素的,它的大小为n,那肯定就是从1到n了(因为盒子的范围就是从1到n)。
此外还有一种情况,如果在op2中有这个元素也代表满了,这是什么意思呢?在op2中存放的编号表示除了这个编号之外的所有盒子编号都放了球,假设t = 1时, x = 2,表示在2号盒子中放入一个小球,那如果x也在op2中,表示除了2号盒子之外的盒子都已经有球了,这样也就是所有的盒子都有球了。

如果是第2种类型,t = 2,代表向除了编号为 x 的其他 n−1 盒子里放入一个小球。把x插入到op2里面。
此时如果op2中的元素个数大于1,则代表满了。比如说原来op2中有一个元素2,它表示除了2号盒子之外都放了一个小球,此时如果在有一个元素放进来,比如4,表示除了4号盒子之外都放了小球,当然前一个空的2号盒子也放了小球,这样所有盒子都放了小球;
还有一种情况,如果op2中原来为空,插入了第一个元素x,如果op1中也有这个元素的话,也代表满了。这一点很好理解,比如说原来op2中有一个元素2,它表示除了2号盒子之外都放了一个小球,2号盒子是空的,如果op1中有2,表示之前已经在op1中放小球了。

如果满的话会输出操作次数然后返回。如果for循环结束了,还没有返回则代表没有满,输出-1;

参考代码:

#include <iostream>
#include <unordered_set>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;

    unordered_set<int> op1, op2;

    for (int i = 1; i <= m; i++) {
        int t, x;
        cin >> t >> x;

        if (t == 1) {
            op1.insert(x);

            if (op1.size() == n || op2.find(x) != op2.end()) {
                cout << i << endl;
                return 0;
            }
        } else {
            op2.insert(x);

            if (op2.size() > 1 || op1.find(x) != op1.end()) {
                cout << i << endl;
                return 0;
            }
        }
    }

    cout << -1 << endl;

    return 0;
}

还有一种实现方式供参考,超时了,或者有什么好的改进方法欢迎评论区留言:

#include <iostream>
#include <unordered_set>

int main() {
    int n, m;
    std::cin >> n >> m;

    std::unordered_set<int> mySet;
    for (int i = 1; i <= n; ++i) {
        mySet.insert(i);
    }

    int i;
    for (i = 1; i <= m; ++i) {
        int operation;
        std::cin >> operation;

        if (operation == 1) {
            int num;
            std::cin >> num;
            mySet.erase(num);

            if (mySet.empty()) {
                break;
            }
        } else {
            int x;
            std::cin >> x;

            if (mySet.find(x) == mySet.end()) {
                break;
            }

            mySet.clear();
            mySet.insert(x);
        }
    }

    std::cout << (i > m ? -1 : i) << std::endl;

    return 0;
}

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值