拼多多2021笔试真题 多多的骰子组合

拼多多2021笔试真题 多多的骰子组合

题目

两个骰子为同类的定义是:
将其中一个骰子通过若干次上下、左右或前后翻转后,其与另一个骰子对应的6面数字均相等。

输入描述:
第一行1个整数N,表示骰子的数量。
(1 <= N <= 1,000)
接下来N行,每行6个数字(1~6,且各不相同)
其中第i行表示第i个骰子当前上、下、左、右、前、后这6面的数字。

输出描述:
共2行:
第一行1个整数M,表示不同种类的骰子的个数
第二行M个整数,由大到小排序,表示每个种类的骰子的数量

例1:

输入例子1:
2
1 2 3 4 5 6
1 2 6 5 3 4

输出例子1:
1
2

例子说明1:
第二个骰子相当于是第一个骰子从左向右旋转了一面得到,属于同类。

例2:

输入例子2:
3
1 2 3 4 5 6
1 2 6 5 3 4
1 2 3 4 6 5

输出例子2:
2
2 1

例子说明2:
第三个骰子无法通过任何旋转变换成第一个或第二个骰子。

例3:

输入例子3:
10
2 5 1 3 4 6
5 4 3 2 1 6
1 4 6 2 3 5
1 5 6 3 4 2
6 4 2 1 5 3
3 6 4 5 2 1
1 6 3 4 2 5
5 1 4 2 6 3
6 2 3 1 5 4
5 3 6 1 4 2

输出例子3:
9
2 1 1 1 1 1 1 1 1

例子说明3:
只有第4个骰子(1 5 6 3 4 2)与第8个骰子(5 1 4 2 6 3)属于同一类。

一种可能的变换方式:

  1. 首先从右向左翻转1次
    (1 5 6 3 4 2) -> (1 5 4 2 3 6)
  2. 然后从上向下翻转2次
    (1 5 4 2 3 6) -> (6 3 4 2 1 5) -> (5 1 4 2 6 3)

思路

先确定一面,比如先确定1所在的面。那1的对面的数字有5种可能:2,3,4,5,6。剩下1的周围的4面有几种可能呢?先把剩下的4个数字排列组合,即4! = 24,其中每4种是重复的,所以有24 / 4 = 6种。总共就是5*6 = 30种骰子。

可以根据上面的思路判断是否是同一类。先找到1所在的面,根据1的对面的数字判断是5大类当中的哪种,再根据1周围的一圈判断是6小类的哪种。

很容易可以找到1及其对面。下面是不同情况1周围的面的提取顺序:

1
1
1
1
1
1

要将周围四面提取到一个int数组ring(数组从0开始)中备用,有两种方法可以实现:
1.按顺序 从1及其对面的后面开始提取到ring中(到最后又循环到前面)。交换ring[1]与ring[2]。如果1的位置大于1对面的位置(即上表2,4,6行),就交换ring[1]与ring[3]。
2. 从头开始提取到ring中,如果是1或1对面则跳过。交换ring[1]与ring[2]。如果是上表2,3,6行情况,就交换ring[1]与ring[3]。

提取完后判断是不是同一个环就可以了(如3456与4563是一个环)。

总结:先判断1的对面,再判断1的周围一圈

c++代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXTYPE = 30;
int type[30][5] = {0}, typenum[30] = {0}, typenumsum = 0;
void solve(int *temp)
{
    int i, j, b1 = 0, b2 = 0, ring[5] = {0}, rn = 0;
    for (i = 0; i < 6; i += 2)
    {
        j = i + 1;
        if (temp[i] == 1) {b1 = i; b2 = j;}
        else if (temp[j] == 1) {b1 = j; b2 = i;}
        else
        {
            ring[rn++] = temp[i];
            ring[rn++] = temp[j];
        }
    }
    swap(ring[1], ring[2]);
    if ((b1 < b2) ^ (b1/2 == 1)) swap(ring[1], ring[3]);

    for (int i = 1; i < 4; i++) if (ring[i] < ring[ring[4]]) ring[4] = i;

    i = (temp[b2] - 2) * 6;
    for (int j = 0; j < 6; j++)
    {
        if (typenum[i+j] == 0)
        {
            for (int k = 0; k < 5; k++) type[i+j][k] = ring[k];
            typenum[i+j]++;
            typenumsum++;
            break;
        }
        else
        {
            int flag = 1;
            for (int k = 0; k < 4; k++)
            {
                int k1 = (type[i+j][4] + k) % 4;
                int k2 = (ring[4] + k) % 4;
                if (type[i+j][k1] != ring[k2])
                {
                    flag = 0;
                    break;
                }
            }
            if (flag)
            {
                typenum[i+j]++;
                break;
            }
        }
    }
}
int main()
{
    int n;
    scanf("%d", &n);
    int temp[6];
    while (n--)
    {
        for (int i = 0; i < 6; i++) scanf("%d", temp+i);
        solve(temp);
    }
    sort(typenum, typenum + 30);
    printf("%d\n", typenumsum);
    for (int i = 29; i > -1 && typenum[i]  > 0; i--) printf("%d ", typenum[i]);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值