试试手气(详解版)

sz.png

我们知道一个骰子有 6 个面,分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状态,即它们朝上一面的点数,让你一把抓起摇出另一套结果。假设你摇骰子的手段特别精妙,每次摇出的结果都满足以下两个条件:

  • 1、每个骰子摇出的点数都跟它之前任何一次出现的点数不同;
  • 2、在满足条件 1 的前提下,每次都能让每个骰子得到可能得到的最大点数。

那么你应该可以预知自己第 n 次(1≤n≤5)摇出的结果。

输入格式:

输入第一行给出 6 个骰子的初始点数,即 [1,6] 之间的整数,数字间以空格分隔;第二行给出摇的次数 n(1≤n≤5)。

输出格式:

在一行中顺序列出第 n 次摇出的每个骰子的点数。数字间必须以 1 个空格分隔,行首位不得有多余空格。

输入样例:

3 6 5 4 1 4
3

输出样例:

4 3 3 3 4 3

样例解释:

这 3 次摇出的结果依次为:

6 5 6 6 6 6
5 4 4 5 5 5
4 3 3 3 4 3

 浅说:这道题有两种做法,模拟法和数学推导法,小假在下面都做了对思路和步骤详细地讲解,方便大家理解~

模拟法

1. 定义全局变量
bool arr[10][10];
int n, temp;
  • arr[10][10]:这是一个二维数组,用于记录每个骰子的点数使用情况。arr[i][j] 表示第 i 个骰子是否曾经出现过点数 jarr[i][j] = true 表示第 i 个骰子曾经出现过点数 j

  • 数组大小为 [10][10],是为了方便索引(骰子编号从 1 到 6,点数从 1 到 6)。

  • n:表示摇骰子的次数。

  • temp:临时变量,用于读取输入的点数。


2. 初始化骰子的初始状态
for (int i = 1; i <= 6; i++) {
    cin >> temp;
    arr[i][temp] = true;
}
  • 这个循环用于读取 6 个骰子的初始点数,并记录在 arr 数组中。

  • i 表示骰子的编号(从 1 到 6)。

  • temp 是当前骰子的初始点数。

  • arr[i][temp] = true:表示第 i 个骰子已经出现过点数 temp


3. 读取摇骰子的次数
cin >> n;

读取用户输入的摇骰子次数 n


4. 模拟摇骰子的过程
for (int k = 1; k < n; k++) {
    for (int i = 1; i <= 6; i++) {
        for (int j = 6; j >= 1; j--) {
            if (arr[i][j] == false) {
                arr[i][j] = true;
                break;
            }
        }
    }
}
  • 这个部分模拟了摇骰子的过程。

  • 外层循环 for (int k = 1; k < n; k++):表示摇骰子的次数。循环执行 n-1 次,因为第一次摇骰子的结果已经在初始化阶段记录了。

  • 中层循环 for (int i = 1; i <= 6; i++):遍历每个骰子(编号从 1 到 6)。

  • 内层循环 for (int j = 6; j >= 1; j--):从大到小遍历可能的点数(从 6 到 1)。

  • break:跳出内层循环,继续处理下一个骰子。

  • arr[i][j] = true:标记第 i 个骰子已经出现过点数 j

  • if (arr[i][j] == false):如果第 i 个骰子没有出现过点数 j,则选择这个点数。

  • 核心逻辑

  • 每次摇骰子时,从大到小选择未被使用过的点数。

  • 这样可以保证每次摇出的点数都是可能的最大值,并且不与之前的结果重复。


5. 输出第 n 次摇骰子的结果
for (int i = 1; i <= 6; i++) {
    for (int j = 6; j >= 1; j--) {
        if (arr[i][j] != true) {
            cout << j << ((i != 6) ? " " : "");
            break;
        }
    }
}
  • 这个部分用于输出第 n 次摇骰子的结果。

  • 外层循环 for (int i = 1; i <= 6; i++):遍历每个骰子(编号从 1 到 6)。

  • 内层循环 for (int j = 6; j >= 1; j--):从大到小遍历可能的点数(从 6 到 1)。

  • break:跳出内层循环,继续处理下一个骰子。

  • ((i != 6) ? " " : ""):控制输出格式,确保每个点数之间有一个空格,且行末没有多余的空格。

  • cout << j:输出点数 j

  • if (arr[i][j] != true):如果第 i 个骰子没有出现过点数 j,则选择这个点数。


示例运行过程

输入:
3 6 5 4 1 4
3
初始化:
  • 初始状态:骰子的点数分别为 3, 6, 5, 4, 1, 4。

  • arr 数组的初始状态:

    arr[1][3] = true
    arr[2][6] = true
    arr[3][5] = true
    arr[4][4] = true
    arr[5][1] = true
    arr[6][4] = true
第一次摇骰子(k = 1):
  • 每个骰子选择可能的最大点数,且不与初始状态重复。

  • 结果:6, 5, 6, 6, 6, 6。

  • 更新 arr 数组:

    arr[1][6] = true
    arr[2][5] = true
    arr[3][6] = true
    arr[4][6] = true
    arr[5][6] = true
    arr[6][6] = true
第二次摇骰子(k = 2):
  • 每个骰子选择可能的最大点数,且不与之前的结果重复。

  • 结果:5, 4, 4, 5, 5, 5。

  • 更新 arr 数组:

    arr[1][5] = true
    arr[2][4] = true
    arr[3][4] = true
    arr[4][5] = true
    arr[5][5] = true
    arr[6][5] = true
第三次摇骰子(k = 3):
  • 每个骰子选择可能的最大点数,且不与之前的结果重复。

  • 结果:4, 3, 3, 3, 4, 3。

  • 更新 arr 数组:

    arr[1][4] = true
    arr[2][3] = true
    arr[3][3] = true
    arr[4][3] = true
    arr[5][4] = true
    arr[6][3] = true
输出:
4 3 3 3 4 3

完整代码

#include<bits/stdc++.h>
using namespace std;
bool arr[10][10];
int n,temp;
int main(){
    for(int i = 1;i <= 6;i++){
        cin>>temp;
        arr[i][temp] = true;
    }
    cin>>n;
    for(int k = 1;k < n;k++){
        for(int i = 1;i <= 6;i++){
            for(int j = 6;j >= 1;j--){
                if(arr[i][j] == false){
                    arr[i][j] = true;
                    break;
                }
            }
         }
    }
    for(int i = 1;i <= 6;i++){
        for(int j = 6;j >= 1;j--){
            if(arr[i][j] != true){
                cout<< j <<((i != 6) ? " " :"");
                break;
            }
        }
    }
    return 0;
}

数学推导法

代码解析

1.输入部分

  • 首先,代码读取 6 个骰子的初始点数,并存储在数组 arr 中。
  • 然后,读取摇骰子的次数 n

2.计算部分

  • 对于每个骰子,代码计算第 n 次摇骰子后的点数。计算的核心逻辑如下:

  • m = 7 - n:这个公式用于计算每个骰子在第 n 次摇骰子时的“基础值”。这个基础值是基于摇骰子的次数 n 来确定的。

  • if (m <= arr[i]) m--;:如果计算出的基础值 m 小于或等于骰子的初始值 arr[i],则将 m 减 1。这是因为题目要求每个骰子摇出的点数必须与之前所有出现的点数不同,因此如果基础值 m 已经出现在初始状态中,就需要调整 m 的值。

3.输出部分

  • 代码逐个输出每个骰子在第 n 次摇骰子后的点数,并在数字之间添加空格。

详细解释

  • 基础值 m = 7 - n

    • 这个公式的目的是为了确保每次摇骰子时,骰子的点数尽可能大。由于骰子的点数是 1 到 6,因此 7 - n 可以确保在每次摇骰子时,骰子的点数逐渐减小。

    • 例如,当 n = 1 时,m = 6,即第一次摇骰子时,骰子的点数尽可能大(6)。

    • 当 n = 2 时,m = 5,即第二次摇骰子时,骰子的点数尽可能大(5),但必须与第一次的点数不同。

  • 调整基础值 m

    • 如果计算出的基础值 m 小于或等于骰子的初始值 arr[i],则需要将 m 减 1。这是因为题目要求每个骰子摇出的点数必须与之前所有出现的点数不同。

    • 例如,假设初始值为 3,当 n = 3 时,m = 4。由于 4 大于 3,因此不需要调整。但如果初始值为 4m = 4 时,由于 4 已经出现在初始状态中,因此需要将 m 减 1,得到 3

示例解释

以输入样例为例:

3 6 5 4 1 4
3
  • 初始状态为 [3, 6, 5, 4, 1, 4]

  • 摇骰子的次数 n = 3

对于每个骰子,计算第 3 次摇骰子后的点数:

  1. 第一个骰子初始值为 3m = 7 - 3 = 4。由于 4 > 3,不需要调整,结果为 4

  2. 第二个骰子初始值为 6m = 4。由于 4 <= 6,需要将 m 减 1,结果为 3

  3. 第三个骰子初始值为 5m = 4。由于 4 <= 5,需要将 m 减 1,结果为 3

  4. 第四个骰子初始值为 4m = 4。由于 4 <= 4,需要将 m 减 1,结果为 3

  5. 第五个骰子初始值为 1m = 4。由于 4 > 1,不需要调整,结果为 4

  6. 第六个骰子初始值为 4m = 4。由于 4 <= 4,需要将 m 减 1,结果为 3

因此,第 3 次摇骰子的结果为 [4, 3, 3, 3, 4, 3],与样例输出一致。

完整代码

#include <bits/stdc++.h>
using namespace std;
int main() {
    int arr[6], n;
    for (int i = 0; i < 6; i++) {
        cin>>arr[i];
    }
    cin>>n;
    for (int i = 0; i < 6; i++) {
        int m = 7 - n; // 基础值
        if (m <= arr[i]) m--; // 如果基础值小于等于初始值,则减 1 
        cout<<m;
        if (i != 5) cout<<" ";
    }
    return 0;
}

如果小假的内容对你有帮助,请点赞评论收藏。创作不易,大家的支持就是我坚持下去的动力!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小假

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值