POJ-1029 False coin (模拟与暴力)

 算法定义:算是模拟题

描述

“金条”银行从可靠来源获得信息,在他们最后一组 N 枚硬币中,恰好有一枚是假币,其重量与其他硬币不同(而其他所有硬币的重量都相同)。经济危机过后,他们只有一架简单的天平(如图所示)。使用这架天平,人们能够确定左盘中物体的重量是小于、大于还是等于右盘中物体的重量。
为了检测假币,银行员工用从 1 到 N 的整数对所有硬币进行编号,从而为每枚硬币分配一个唯一的整数标识符。之后,他们开始通过在左盘和右盘中放置相等数量的硬币来称量各种硬币组。硬币的标识符和称重结果都被仔细记录下来。
您要编写一个程序,帮助银行员工使用这些称重结果确定假币的标识符。

输入

输入文件的第一行包含两个整数 N 和 K,它们之间用空格分隔,其中 N 是硬币的数量(2<=N<=1000),K 是满足的权重数(1<=K<=100)。接下来的 2K 行描述了所有的权重。连续两行描述了每个权重。第一行以数字 Pi(1<=Pi<=N/2)开头,代表放在左盘和右盘中的硬币数量,后跟放在左盘中的硬币的 Pi 标识符和放在右盘中的硬币的 Pi 标识符。所有数字都用空格分隔。第二行包含以下字符之一:“<”、“>”或“=”。它代表了加权的结果:
'<'表示左盘中的硬币重量小于右盘中的硬币重量,
'>'表示左盘中的硬币重量大于右盘中的硬币重量,
'='表示左盘中的硬币重量等于右盘中的硬币重量。

输出

如果根据给定的权重结果无法找到假硬币,则将假硬币的标识符或 0 写入输出文件。

示例输入

5 3
2 1 2 3 4
<
1 1 4
=
1 2 5
=

示例输出

3

题目介绍:

对第一次看的小朋友我先讲一下这个题的意思第一行有两个数是n和k对应示例5 和 3 说明有5个硬币 3对于的是有三个公式 他们的关系可以是< = >这三个关系,并且有且仅有一个是假币其余都是真币质量相等。每个银币都有编号 1 2 3 4 5

     对于输入 5 3,表示有5枚硬币和3组称量结果。

  1. 第一组称量结果

    • 左盘放置硬币1和硬币2,右盘放置硬币3和硬币4。
    • 结果为 <,表示左盘的总重量小于右盘的总重量。
    • 可能的解释是,假币要么是左盘的硬币1或硬币2,要么是右盘的硬币3或硬币4。
  2. 第二组称量结果

    • 左盘放置硬币1,右盘放置硬币4。
    • 结果为 =,表示左右盘的总重量相等。
    • 因此,硬币1和硬币4都不可能是假币。
  3. 第三组称量结果

    • 左盘放置硬币2,右盘放置硬币5。
    • 结果为 =,表示左右盘的总重量相等。
    • 因此,硬币2和硬币5都不可能是假币。

根据这些称量结果,唯一可能是假币的是硬币3,因为它在所有称量中从未被称为轻硬币或重硬币。

题目分析和讲解:

这里直接调用北理视频的讲解b站可搜

分析: 结果为等号两边一定是真硬币,结果为不等号肯定含有假硬币所以对于所有的不等式,将轻硬币放在lightCoins里,将重硬币放在heavyCoins里, 因为只有一个假硬币,且假硬币不会一会儿轻一会儿重,所以最后假硬币的出现在lightCoins或者HeavyCoins的次数一定和不等号出现的次数相等。 若恰有一个满足条件的疑似假币,则输出

好的总结一下

等于就是真币排除,不等于进行分组lightCoins和heavyCoins,并且用容器装起来然后计算次数类似哈希表(但这种方法不涉及哈希表,而是使用简单的数组进行计数)。然后先是排除真币次数

  • 大体思路
  • 数据结构初始化

    • 使用三个数组来记录硬币的称重情况:
      • lighter[i]:记录硬币 i 被称为轻硬币的次数。
      • heavier[i]:记录硬币 i 被称为重硬币的次数。
      • isTrue[i]:记录硬币 i 是否被确定为真币,初始为 true
  • 处理称重结果

    • 对于 < 的结果:左盘硬币轻,右盘硬币重,分别更新 lighterheavier 数组。
    • 对于 > 的结果:左盘硬币重,右盘硬币轻,同样更新 lighterheavier 数组。
    • 对于 = 的结果:左右盘硬币重量相等,这些硬币都有可能是真币,因此标记为非假币并清除其在 lighterheavier 数组中的计数。
  • 查找唯一假币

    • 遍历每枚硬币,如果 lighter[i]heavier[i] 等于 0,则表示硬币 i 在所有称重结果中都未被称为轻硬币或重硬币,因此 i 可能是假币。
  • 输出结果

    • 输出找到的假币编号。
  • 麻辣鸡的,改了十几遍终于是代码改出来了改到了凌晨3点,好了我对这个代码进行一个细节讲解首先先计算<和>的进行vector++,左边加左右边加右。最后最后!!(就这破玩意我想急毛半天)最后算等于,就是都是真币直接把计算的vector++的全部变成0.这样就只有假币没有变成0。好的最后只要进行遍历找出那个等于1的出现次数就可以了(就是那个唯一假币)

  • #include <iostream>
    #include <vector>
    using namespace std;
    
    int main() {
        int N, K;
        cin >> N >> K;
    
        vector<int> lighter(N + 1, 0); // 记录每个硬币被称为轻硬币的次数
        vector<int> heavier(N + 1, 0); // 记录每个硬币被称为重硬币的次数
        vector<bool> isTrue(N + 1, true); // 标记每个硬币是否被确定为真币
    
        for (int k = 0; k < K; ++k) {
            int P;
            cin >> P;
            vector<int> left(P), right(P);
            char result;
    
            for (int i = 0; i < P; ++i) {
                cin >> left[i];
            }
            for (int i = 0; i < P; ++i) {
                cin >> right[i];
            }
            cin >> result;
    
            if (result == '<') {
                for (int i = 0; i < P; ++i) {
                    ++lighter[left[i]];
                    ++heavier[right[i]];
                }
            } else if (result == '>') {
                for (int i = 0; i < P; ++i) {
                    ++lighter[right[i]];
                    ++heavier[left[i]];
                }
            } else if (result == '=') {
                // 先确定是真币的硬币,并清除它们的计数
                for (int i = 0; i < P; ++i) {
                    if (isTrue[left[i]]) {
                        lighter[left[i]] = 0;
                        heavier[left[i]] = 0;
                    }
                    if (isTrue[right[i]]) {
                        lighter[right[i]] = 0;
                        heavier[right[i]] = 0;
                    }
                    isTrue[left[i]] = false; // 标记为非假币
                    isTrue[right[i]] = false; // 标记为非假币
                }
            }
        }
    
        int fakeCoin = 0;
        for (int i = 1; i <= N; ++i) {
            if (lighter[i] == 0 || heavier[i] == 0) {
                fakeCoin = i;
                break;
            }
        }
    
        cout << fakeCoin << endl;
    
        return 0;
    }
    

  •  感谢观看 ,摸摸几╰( ̄ω ̄o)


  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值