首页 > 试题广场 >

多多的骰子组合

[编程题]多多的骰子组合
  • 热度指数:1687 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
多多君拼团购买了N个骰子,为了方便后面进行活动,多多君需要将这些骰子进行分类。



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

现在多多君想知道不同种类的骰子的数量分别有多少。

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


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

输入

2
1 2 3 4 5 6
1 2 6 5 3 4

输出

1
2

说明

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

输入

3
1 2 3 4 5 6
1 2 6 5 3 4
1 2 3 4 6 5

输出

2
2 1

说明

第三个骰子无法通过任何旋转变换成第一个或第二个骰子。
示例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

输出

9
2 1 1 1 1 1 1 1 1

说明

只有第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)

备注:
对于50%的数据,有: 1 <= N <= 50
对于100%的数据,有:1 <= N <= 1,000
对于每个筛子都搜索一趟搞到对应的那个字典序最小的作为key,开map<KeyType, int> cnt计数即可(此处KeyType为vector<int>
本地跑了下6的全排列,每个排列通过搜索都能得到24中不同的排列,即每24种排列视为1种,总共6!24 = 30总不同的筛子(具体见注释掉的那段代码)

#include <bits/stdc++.h>
using namespace std;

const string dirs[] = {"上","下","左","右","前","后"}; // 默认的顺序
map<string, int> s_idx; // 维护字符串在dirs中的位置

/* 3种不同的旋转方式:
**   例如第一种为
**   [上 -> 右 ], [右 -> 下], [下 -> 左], [左 -> 上]  
**   即        上 -> 右 -> 下 -> 左 -> ...
*/
const string turn[3][4] = {
	{"上","右","下","左"}, /*前后不动*/
	{"上","前","下","后"}, /*左右不动*/
	{"前","右","后","左"}  /*上下不动*/
};


vector<vector<int> > get_nexts(vector<int> vv) {
	/**
	 * 获取vv的3个下一种状态
	 */
	vector<vector<int> > ret;
	for (int i = 0; i < 3; ++i){
		auto v = vv;
		/* 完成“旋转”操作*/
		int t = v[s_idx[turn[i][0]]];
		for (int j = 1; j < 4; ++j){
			v[s_idx[turn[i][j-1]]] = v[s_idx[turn[i][j]]];
		}
		v[s_idx[turn[i][3]]] = t;
		ret.push_back(v);
	}

	return ret;
}

ostream & operator << (ostream &cout, vector<int> v) {
	cout << "[";
	for ( auto i : v ) {
		cout << i << " ";
	}
	cout << "]";

}

vector<int> get_min(vector<int> v) {
	/**
	 * 搜索一趟,获取v通过旋转可达的最小的
	 */
	map<vector<int>, bool> vis;
	queue<vector<int> > q;
	vis[v] = 1;
	q.push(v);
	vector<int> ret = v;
	while (q.size()) {
		vector<int> curr = q.front(); q.pop();
		if ( curr < ret ) {
			ret = curr;
		}
		auto nexts = get_nexts(curr);
		for ( auto next : nexts ) {
			if ( vis.find(next)==vis.end() ) {
				vis[next] = 1;
				q.push(next);
			}
		}
	}
	return ret;
}

int main(int argc, char const *argv[]){

	for (int i = 0; i < 6; ++i){
		s_idx[dirs[i]] = i;
	}

/*
	vector<int> v = {1,2,3,4,5,6};
	set<vector<int>> s;
	do{
		s.insert(get_min(v));
	}while(next_permutation(v.begin(), v.end()));
	for ( auto& item : s ) {
		for(auto i : item ) {
			cout << i << " ";
		}
		cout << "" << endl;
	}
	clog << "s.size() = " << s.size() << endl; //log
	return 0;
//	*/
	int n;
	cin>>n;
	map<vector<int>, int> mp;
	for ( int i = 0; i < n; ++i ) {
		vector<int> v;
		for ( int i = 0; i < 6; ++i ) {
			int x;
			cin>>x;
			v.push_back(x);
		}
		mp[get_min(v)]++;
	}
	vector<int> ans;
	for ( auto &item : mp ) {
		ans.push_back(item.second);
	}
	sort(ans.begin(), ans.end(), 
		[](int a, int b) -> bool {return a>b;}); // 降序
	cout << ans.size() << endl;
	for ( auto i : ans ) {
		cout << i << " ";
	}

	return 0;
}





发表于 2021-05-26 20:25:20 回复(0)
我们取每个骰子:以1作为上面,然后得到侧边四面的4个数字的顺序。
如果任意两个骰子的这个侧面4个数字顺序是一样的,那么这两个骰子就是同类。

比如示例2
骰子1:123456,侧边的四面数字为 3546(或5463、..)
骰子2:126534,侧边的四面数字为 6354(或3546、..)
骰子3:123465,侧边的四面数字为 3645(或6453、..)
调整骰子2的侧边的四面数字顺序 3546,这就和骰子1一样了。(这里为了实现匹配是通过将四位数字转为int型整数,然后取不同顺序中最小的值)

此外结合如下规律:
1. 骰子6面可以分为3对,每对两面,比如 12 、34 、56
2. 骰子按对顺序调换不改变骰子顺序,比如 123456 与 561234 是同一类
3. 举例:骰子为 123456, 1位上面侧边四面为 3564
4. 举例:骰子为 345612, 1位上面侧边四面为 3564
5. 举例:骰子为 213456, 1位上面侧边四面为 6453
6. ...

#include<bits/stdc++.h>
using namespace std;

int main() {
	int N; 
	cin >> N;
	unordered_map<int, int> um;
	for(int n=1; n<=N; ++n){
		int a[6];
		for(int i=0; i<6; ++i) cin >> a[i];
		int val = 0;
		for(int i=0; i<6; ++i) {
			if(a[i]==1) {
				if(i%2==0) 
					val = a[(i+2)%6]*1000 + a[(i+4)%6]*100 + a[(i+3)%6]*10 + a[(i+5)%6];
				else  
					val = a[(i+4)%6]*1000 + a[(i+2)%6]*100 + a[(i+3)%6]*10 + a[(i+1)%6];
				break;
			}
		}

		for(int i=0, tmp = val; i<3; ++i) {
			tmp = tmp/10 + (tmp%10*1000);
			val = min(val, tmp);
		}
		um[val]++;
	}

	vector<int> res;
	for(auto iter : um) res.push_back(iter.second);
	sort(res.begin(), res.end());
	
	cout << res.size() << endl;
	for(int i=res.size()-1; i>=0; --i) cout << res[i] << " ";
	return 0;	
}


编辑于 2021-05-18 21:32:42 回复(4)

贴一个无脑枚举的方法,因为骰子只有 4 种旋转方法,所以每获得一个新的骰子,就 BFS 一下,把所有可能都遍历到(最多可能 24 种?),然后后面如果在遇到一样的,就可以直接判断它属于哪一种了。

记录每一种的数量,最后输出答案即可。

#include <bits/stdc++.h>
#include <cstdio>
#include <functional>
#include <tuple>
#include <unordered_map>
#include <vector>
using namespace std;
struct sieve{
    int up, down, left, right, front, back;
    string to_string() {
        static char t[15];
        // cout << up << ' ' << down << ' ' << left << ' ' << right << ' ' << front << ' ' << back << endl;
        sprintf(t, "%d%d%d%d%d%d", up, down, left, right, front, back);
        return string(t);
    }
};
sieve toUp(sieve s) {
    tie(s.front, s.down, s.back, s.up) = make_tuple(s.down, s.back, s.up, s.front);
    return s;
}
sieve toDown(sieve s) {
    tie(s.front, s.down, s.back, s.up) = make_tuple(s.up, s.front, s.down, s.back);
    return s;
}
sieve toLeft(sieve s) {
    tie(s.front, s.right, s.back, s.left) = make_tuple(s.right, s.back, s.left, s.front);
    return s;
}
sieve toRight(sieve s) {
    tie(s.front, s.right, s.back, s.left) = make_tuple(s.left, s.front, s.right, s.back);
    return s;
}
int main() {
    int n;
    cin >> n;
    // 筛子序列化 -> 种类编号
    unordered_map<string, int> mp;
    vector<int> cnt(n);
    for (int i = 0; i < n; i++) {
        sieve s;
        cin >> s.up >> s.down >> s.left >> s.right >> s.front >> s.back;
        // cout << s.to_string() << endl;
        if (mp.count(s.to_string())) {
            cnt[mp[s.to_string()]]++;
            continue;
        }
        // 种类命名为 i
        cnt[i]++;
        queue<sieve> q;
        q.push(s);
        // cout << "s: " << s.to_string() << endl;
        while (q.size()) {
            auto x = q.front(); q.pop();
            // cout << x.to_string() << endl;
            for (auto &y : vector<sieve>{toUp(x), toDown(x), toLeft(x), toDown(x)}) {
                if (mp.count(y.to_string())) continue;
                mp[y.to_string()] = i;
                q.push(y);
            }
        }
    }
    vector<int> res;
    for (int i = 0; i < n; i++) {
        if (cnt[i] > 0) res.push_back(cnt[i]);
    }
    sort(res.begin(), res.end(), greater<int>());
    cout << res.size() << endl;
    for (auto x : res) {
        cout << x << " ";
    }
}
发表于 2023-03-12 16:32:24 回复(0)
将每一个骰子按一定规律旋转,以 “前后左右上下” 的顺序来看一个骰子 12 34 56
前后固定旋转,可得到
12 34 56
12 56 43
12 43 65
12 65 34
同理,固定左右
56 34 21
21 34 65
65 34 12
12 34 56
固定上下
43 12 56
21 43 56
43 12 56
12 34 56
观察 “12 34 56” 变成 “12 56 43”,”12 65 34“也就是说每一次旋转固定一个面,剩余四个面交换位置,其中“一对”再交换
或者 “12 34 56” 变成 “12 43 65” 其中“两对” 各自交换
那么我们把骰子旋转到“最小”的样子
p1代表前后,p2代表左右, p3代表上下
让 p1最小值 < p2最小值 < p3最小值
让 p1[0]<p1[1] , p2[0]<p2[1]
import collections
n = int(input())
counter = collections.Counter()
finger={}
res = []
for i in range(n):
    l=list(map(int,input().strip().split()))
    p1 = l[:2]
    p2 = l[2:4]
    p3 = l[4:]
    if min(p1)>min(p2):
        p1,p2=p2,p1[::-1]
    if min(p1)>min(p3):
        p1,p3=p3,p1[::-1]
    if min(p2)>min(p3):
        p2,p3=p3,p2[::-1]
    if p1[0]>p1[1]:
        p1,p3=p1[::-1],p3[::-1]
    if p2[0]>p2[1]:
        p2,p3=p2[::-1],p3[::-1]
    s = (p1[0],p1[1],p2[0],p2[1],p3[0],p3[1])
    if s not in finger:
        finger[s]=len(res)
        res.append(1)
    else:
        res[finger[s]]+=1
print(len(res))
res=map(str,sorted(res,reverse=True))
print(' '.join(res))


编辑于 2021-05-22 11:26:53 回复(0)
硬生生把6*4个旋转方式列了出来
n = int(input())

abc = []
for i in range(n):
    line = tuple(map(int, input().split()))
    abc.append(line)


def rotate(a, b, c, d, e, f):
    dt[(a, b, c, d, e, f)] = count
    dt[(a, b, e, f, d, c)] = count
    dt[(a, b, d, c, f, e)] = count
    dt[(a, b, f, e, c, d)] = count


dt = dict()
count = 0
res = []
for nums in abc:
    if nums not in dt:
        res.append(1)
        a, b, c, d, e, f = nums
        rotate(a, b, c, d, e, f)
        rotate(c, d, b, a, e, f)
        rotate(e, f, c, d, b, a)
        rotate(b, a, c, d, f, e)
        rotate(d, c, a, b, e, f)
        rotate(f, e, c, d, a, b)
        count += 1
    else:
        index = dt[nums]
        res[index] += 1
print(count)
res.sort(reverse=True)
for cnt in res:
    print(cnt, end=' ')


编辑于 2024-09-20 22:10:26 回复(0)
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static int getKey(int[] d,int i,int a,int b,int c,int k){
              int ret = 0;
                   if(i==a){
                           ret+=d[a]*1000+d[b]*100+d[c]*10+d[k];
                        }else if(i ==b){
                             ret+=d[b]*1000+d[c]*100+d[k]*10+d[a];
                        }else if (i == c){
                              ret+=d[c]*1000+d[k]*100+d[a]*10+d[b];
                        }else{
                            ret+=d[k]*1000+d[a]*100+d[b]*10+d[c];
                        }

              return ret;
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int  n = in.nextInt();
        Map<Integer, Integer> map = new HashMap<>();
        int[][] input = new int[n][6];
        for (int i = 0 ; i < n; i++) {
            for (int j = 0 ; j < 6 ; j++) {
                input[i][j] = in.nextInt();
            }
        }
        for (int i = 0 ; i < n; i++) {
            //先看1
            int[] d =  input[i];
            for (int j = 0; j < 6; j++) {
                if (d[j] == 1) {
                    //先看下是不是在上

                    if (j == 0) {
                        int key = 100000;
                        int a  = d[1];
                        key += a * 10000;
                        int min = 100;
                        if (a != 2) {
                            min = 2;
                        } else {
                            min = 3;
                        }
                        int index = 0;
                        for (int f = 0; f < 6; f++) {
                            if (d[f] == min) {
                                index = f;
                                break;
                            }
                        }
                        //接下来,从2或3开始顺时针转一圈
                     key+= getKey(d,index,2,4,3,5);
                        if(!map.containsKey(key)){
                            map.put(key,1);
                        }else{
                            map.put(key,map.get(key)+1);
                        }
                    }else if(j==1){
                             int key = 100000;
                        int a  = d[0];
                        key += a * 10000;
                        int min = 100;
                        if (a != 2) {
                            min = 2;
                        } else {
                            min = 3;
                        }
                        int index = 0;
                        for (int f = 0; f < 6; f++) {
                            if (d[f] == min) {
                                index = f;
                                break;
                            }
                        }
                        //接下来,从2或3开始顺时针转一圈
                         key+= getKey(d,index,2,5,3,4);
                        if(!map.containsKey(key)){
                            map.put(key,1);
                        }else{
                            map.put(key,map.get(key)+1);
                        }
                    }else if (j==2){
                      int key = 100000;
                        int a  = d[3];
                        key += a * 10000;
                        int min = 100;
                        if (a != 2) {
                            min = 2;
                        } else {
                            min = 3;
                        }
                        int index = 0;
                        for (int f = 0; f < 6; f++) {
                            if (d[f] == min) {
                                index = f;
                                break;
                            }
                        }
                        //接下来,从2或3开始顺时针转一圈
                         key+= getKey(d,index,0,5,1,4);
                        if(!map.containsKey(key)){
                            map.put(key,1);
                        }else{
                            map.put(key,map.get(key)+1);
                        }
                    }
                    else if (j==3){
                      int key = 100000;
                        int a  = d[2];
                        key += a * 10000;
                        int min = 100;
                        if (a != 2) {
                            min = 2;
                        } else {
                            min = 3;
                        }
                        int index = 0;
                        for (int f = 0; f < 6; f++) {
                            if (d[f] == min) {
                                index = f;
                                break;
                            }
                        }
                        //接下来,从2或3开始顺时针转一圈
                         key+= getKey(d,index,1,5,0,4);
                        if(!map.containsKey(key)){
                            map.put(key,1);
                        }else{
                            map.put(key,map.get(key)+1);
                        }
                    }
                     else if (j==4){
                      int key = 100000;
                        int a  = d[5];
                        key += a * 10000;
                        int min = 100;
                        if (a != 2) {
                            min = 2;
                        } else {
                            min = 3;
                        }
                        int index = 0;
                        for (int f = 0; f < 6; f++) {
                            if (d[f] == min) {
                                index = f;
                                break;
                            }
                        }
                        //接下来,从2或3开始顺时针转一圈
                         key+= getKey(d,index,0,2,1,3);
                        if(!map.containsKey(key)){
                            map.put(key,1);
                        }else{
                            map.put(key,map.get(key)+1);
                        }
                    }
                     else if (j==5){
                      int key = 100000;
                        int a  = d[4];
                        key += a * 10000;
                        int min = 100;
                        if (a != 2) {
                            min = 2;
                        } else {
                            min = 3;
                        }
                        int index = 0;
                        for (int f = 0; f < 6; f++) {
                            if (d[f] == min) {
                                index = f;
                                break;
                            }
                        }
                        //接下来,从2或3开始顺时针转一圈
                         key+= getKey(d,index,0,3,1,2);
                        if(!map.containsKey(key)){
                            map.put(key,1);
                        }else{
                            map.put(key,map.get(key)+1);
                        }
                    }
                    break;
                }

            }
        }
        List<Integer> list = new ArrayList<>(map.values());
        Collections.sort(list,new Comparator<Integer>(){
            public int compare(Integer s,Integer t1 ){
                return t1-s;
            }
        });
        
       System.out.println(map.keySet().size());
    for(int i = 0 ; i < list.size();i++){
        System.out.print(list.get(i)+" ");
    }
    }
}

发表于 2024-08-20 00:23:56 回复(0)
Java 硬模拟,骰子就两种旋转方式,水平和垂直。每个骰子都固定top为1,固定左面小于右面,前面小于后面,则每类骰子的情况唯一。
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = Integer.parseInt(in.nextLine());
        HashMap<String, Integer> myhashMap = new HashMap<>();
        for (int i = 0; i < n; i++) {
            String line = in.nextLine();
            Touzi temp = new Touzi(line);
          
            myhashMap.put(temp.toString(),myhashMap.getOrDefault(temp.toString(),0)+1);
        }
        System.out.println(myhashMap.keySet().size());
        ArrayList<Integer> result=new ArrayList<>();
        for(String key:myhashMap.keySet()){
            result.add(myhashMap.get(key));
        }
        result.sort((x,y)->y-x);
        for(Integer i:result){
            System.out.print(i+" ");
        }
    }
}
class Touzi {
    public int top;
    public int bottom;
    public int left;
    public int right;
    public int front;
    public int behind;
    Touzi(String line) {
        String [] temps = line.split(" ");
        top = Integer.parseInt(temps[0]);
        bottom = Integer.parseInt(temps[1]);
        left = Integer.parseInt(temps[2]);
        right = Integer.parseInt(temps[3]);
        front = Integer.parseInt(temps[4]);
        behind = Integer.parseInt(temps[5]);
        while (top != 1) {
            if (bottom == 1 || behind == 1 || front == 1) {
                verticalswap();
            } else {
                horizontalswap();
            }
        }
        while (left > right||front>behind) {
            horizontalswap();
        }
    }
    public String toString() {
        return top+ "" + bottom +""+ left+"" + right+"" + front+"" + behind ;
    }
    public void horizontalswap() {
        int templeft = this.left;
        int tempright = this.right;
        int tempfront = this.front;
        int tempbehind = this.behind;
        this.left = tempfront;
        this.behind = templeft;
        this.right = tempbehind;
        this.front = tempright;
    }
    public void verticalswap() {
        int tempfront = this.front;
        int tempbehind = this.behind;
        int temptop = this.top;
        int tempbottom = this.bottom;
        this.front = temptop;
        this.bottom = tempfront;
        this.behind = tempbottom;
        this.top = tempbehind;
    }
}


发表于 2024-08-11 13:32:01 回复(0)
取一个骰子的点数1为基准面,顺时针取基准面周围的四个面,如果两个骰子基准面周围四个面顺序相同,则为同一个骰子。可以用一个Hash表记录每种骰子的个数,为了方便比较Hash表的key,一个面占至少三位,可以把一个Int分成四部分,从高位到低位分别记录周围四个面的点数,同时为了统一,四个面按顺时针顺序从最小点数开始记录。
具体如下:
一个骰子点数为1的面,下标为0,则它四个面按顺时针下标分别为:2,5,3,4,
下标为1,四个面按顺时针分别为:2,4,3,5,...
可以用一个二维数组记录对应下标:ids = {{2,5,3,4},{2,4,3,5},{1,5,0,4},{1,4,0,5},{0,3,1,2},{0,2,1,3}},
对每个骰子,先找到点数1的面的下标 i,则其四个面下标为 ids[ i ],再从四个面中的最小点数开始遍历,假设得到的四个面点数分别为 a,b,c,d,那么可以让 key = (a<<12) + (b<<8) + (c<<4) + d,用Hash表记录这种骰子的数量即可。

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = in.nextInt();
        int[][] tou = new int[n][6];
        for(int i=0;i<n;++i){
            for(int j=0;j<6;++j){
                tou[i][j] = in.nextInt();
            }
        }
        // 找到其中一面,以其为基准,顺时针从最小面开始的四个面如果相同,则为同一个骰子
        // 以上下左右前后为基准面时,顺时针四个面的下标
        int[][] indexes = new int[][]{{2,5,3,4},{2,4,3,5},{1,5,0,4},{1,4,0,5},{0,3,1,2},{0,2,1,3}};
        // 用Hashmap记录以 1 为基准面时,顺时针的四个面,5可以用4位表示,因此按从高位到低位的顺序记录顺时针的四个面作为key
        Map<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<n;++i){
            int index = 0;
            for(int j=0;j<6;++j){
                if(tou[i][j] == 1){
                    index = j;
                    break;
                }
            }
            // 基准面 1 的下标为 index,顺时针四个面下标为indexes[index],为了一致,选择从四个面中点数最小的作为起始面
            int start = 0;
            for(int k=1;k<4;++k){
                if(tou[i][indexes[index][k]]<tou[i][indexes[index][start]]){
                    start = k;
                }
            }
            int count = 4;
            int key = 0;
            // 将四个面组成key
            while(count-->0){
                int curPoint = tou[i][indexes[index][start++]];
                key = (key<<4) + curPoint;
                if(start==4){
                    start = 0;
                }
            }
            map.put(key, map.getOrDefault(key,0)+1);
        }
        Integer[] res = new Integer[map.size()];
        int index = 0;
        for(Integer key:map.keySet()){
            res[index++] = map.get(key);
        }
        Arrays.sort(res, (a,b)->b.compareTo(a));
        System.out.println(res.length);
        for(int i=0;i<res.length;++i){
            System.out.print(res[i]+" ");
        }
    }
}
发表于 2024-05-09 14:39:38 回复(0)
题面中存在6种状态:
面对骰子正前方:1,2,3,4,5,6
下翻:6,5,3,4,1,2
上翻:5,6,3,4,2,1
左翻:4,3,1,2,5,6
右翻:3,4,2,1,5,6
左旋:1,2,5,6,4,3
右旋:1,2,6,5,3,4
其中上翻可由下翻推导而来,左翻可由右翻推导而来,左旋可由右旋推导而来
所以我们可以将上下翻,左右翻,左右旋归结为一种状态并分别固定,
我们约定
上下翻归结为:5,6,3,4,2,1
左右翻归结为:3,4,2,1,5,6
左右旋归结为:1,2,5,6,4,3
目的在于保证状态转换后的局部优先有序性
    解释:每一种状态转换都会有一对数字的状态不变
                那么我们每一次状态转换后,要保证发生
                转换的那两对数字,位于较前面的一对数字
                是按照从小到大排列的。
所以我们对一个骰子构建一个结构体 dice,其中含三种转换方法
dice::dau,即 上下翻转 状态归结
dice::lar, 即左右翻转状态归结
dice::oao,即左右旋转状态归结
而对于 dice 的最终状态,我们要依靠这三种方法得到最理想的骰子状态:
    即骰子的三组数字状态有序排列。
给出代码如下:
时间复杂度我们可以达到 O(nlogn).
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

map<vector<pair<int, int>>, int> p;

struct dice {
	vector<pair<int, int>> v;
	vector<pair<int, int>> f;
	dice(vector<pair<int, int>> v) : v(v)
	{ }
	void dau() {
		f = {v[2], v[1], {v[0].second, v[0].first}};
		v = f;
		if (v[0].first > v[0].second) {
			swap(v[0].first, v[0].second);
			swap(v[2].first, v[2].second);
		}
	}
	void lar() {
		f = {v[1], {v[0].second, v[0].first}, v[2]};
		v = f;
		if(v[0].first > v[0].second) {
			swap(v[0].first, v[0].second);
			swap(v[1].first, v[1].second);
		}
	}
	void oao() {
		f = {v[0], v[2], {v[1].second, v[1].first}};
		v = f;
		if (v[1].first > v[1].second) {
			swap(v[1].first, v[1].second);
			swap(v[2].first, v[2].second);
		}
	}
	void find() {
		int idx = 0;
		for (; idx < 3; idx++) {
			if (v[idx].first == 1 || v[idx].second == 1) break;
		}
		if (idx == 0) {
			lar();
			lar();
			oao();
			if (v[1] > v[2] || v[1].first > v[2].second) oao();
		}
		else if (idx == 1) {
			lar();
			oao();
			if (v[1] > v[2] || v[1].first > v[2].second) oao();
		}
		else {
			dau();
			oao();
			if (v[1] > v[2] || v[1].first > v[2].second) oao();
		}
	}
};
vector<int> ans;

int main() {
	int n;
	cin >> n;
	int a, b, c, d, e, f;
	for (int i = 0; i < n; i++) {
		cin >> a >> b >> c >> d >> e >> f;
		dice x({{a, b}, {c, d}, {e, f}});
		x.find();
		p[x.v]++;
	}
	for (auto &t: p) {
		ans.push_back(t.second);
	}
	sort(ans.begin(), ans.end(), greater<int>());
	cout << ans.size() << endl;
	for (auto &t: ans) cout << t << " ";
}


发表于 2023-03-12 00:17:36 回复(0)

和大家一样的想法,想法子将骰子固定住,固定两个面就行了,我是1在上面,先固定上下两面,前后左右四面保证最小的在左侧,怎么转的就稍微想一下就行,很简单

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[][] matrix = new int[n][6];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 6; j++) {
                matrix[i][j] = sc.nextInt();
            }
        }

       getDiffNum(matrix, n);
    }

    private static void getDiffNum(int[][] matrix, int n) {
        for (int i = 0; i < n; i++) {
            // 将数据全转成 1 在上且左侧比右侧小的排序
            int[] nums = matrix[i];
            for (int j = 0; j < 6; j++) {
                if (1 == nums[j]) {
                    rotate(nums, j);
                }
            }
        }

        Map<String, Integer> map = new HashMap<>();
        // 进行次数统计
        for (int i = 0; i < n; i++) {
            int[] nums = matrix[i];
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < 6; j++) {
                sb.append(nums[j]);
            }

            String key = sb.toString();
            if (map.containsKey(key)) {
                map.put(key, 1 + map.get(key));
            } else {
                map.put(key, 1);
            }
        }

        System.out.println(map.size());
        map.values().stream().sorted((t1, t2) -> {
            return t2 - t1;
        }).forEach(item -> {
            System.out.print(item + " ");
        });
        System.out.println();
    }

    private static void rotate(int[] nums, int pos) {
        if (1 == pos) {
            swap(nums, 0, 1);
            swap(nums, 4, 5);
        } else if (2 == pos) {
            swap(nums, 0, 2);
            swap(nums, 1, 3);
            swap(nums, 2, 3);
        } else if (3 == pos) {
            swap(nums, 0, 2);
            swap(nums, 1, 3);
            swap(nums, 0, 1);
        } else if (4 == pos) {
            swap(nums, 0, 4);
            swap(nums, 1, 5);
            swap(nums, 4, 5);
        } else if (5 == pos) {
            swap(nums, 0, 4);
            swap(nums, 1, 5);
            swap(nums, 0, 1);

        }
        rotateLeftMin(nums);
    }

    private static void rotateLeftMin(int[] nums) {
        int idx = -1, min = Integer.MAX_VALUE;
        for (int i = 2; i < 6; i++) {
            if (min > nums[i]) {
                min = nums[i];
                idx = i;
            }
        }

        rotate2(nums, idx);
    }

    /**
     * 将第三个位置置为后四个最小值
     * @param nums
     * @param idx
     */
    private static void rotate2(int[] nums, int idx) {
        if (3 == idx) {
             swap(nums, 2,3);
             swap(nums, 4,5);
        } else if (4 == idx) {
            swap(nums, 2,4);
            swap(nums, 3,5);
            swap(nums, 4,5);
        } else if (5 == idx) {
            swap(nums, 2,4);
            swap(nums, 3,5);
            swap(nums, 2,3);
        }
    }


    private static void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}
发表于 2022-12-21 00:09:03 回复(1)
将每个骰子固定两个面,骰子的排序就是固定的,我选择将1转到上,剩下最大的转到左边

#include<bits/stdc++.h>
using namespace std;
string i2j(vector<int> a){
    int id1;
    for(int i=0;i<6;i++){
        if(a[i]==1) {
            id1=i;
            break;
        }
    }
    if(id1>1){
        if(id1%2==0){
            swap(a[id1],a[0]);
            swap(a[id1+1],a[1]);
            swap(a[id1+1],a[id1]);
        }
        else{
            swap(a[id1],a[1]);
            swap(a[id1-1],a[0]);
            swap(a[1],a[0]);
        }
    }
    else{
        if(id1==1){
            swap(a[0],a[1]);
            swap(a[2],a[3]);
        }
    }
    int num_next=6;
    if(a[1]==6){
        num_next=5;
    }
    int id_next;
    for(int i=2;i<6;i++){
        if(a[i]==num_next){
            id_next=i;
            break;
        }
    }
    if(id_next!=2){
        if(id_next==3){
            swap(a[2],a[3]);
            swap(a[4],a[5]);
        }
        else if(id_next==4){
            swap(a[2],a[4]);
            swap(a[3],a[5]);
            swap(a[4],a[5]);
        }
        else{
            swap(a[2],a[4]);
            swap(a[3],a[5]);
            swap(a[2],a[3]);
        }
    }
    string out="";
    for(int i=0;i<6;i++){
        out+=to_string(a[i]);
    }
    return out;
}
int main(){
    int num=0;
    cin>>num;
    unordered_map<string , int> a;
    for(int i=0;i<num;i++){
        vector<int> tmp(6,0);
        for(int j=0;j<6;j++){
            cin>>tmp[j];
        }
        string b=i2j(tmp);
        a[b]++;
    }
    cout<<a.size()<<endl;
    vector<int > c;
    for(auto i:a){
        c.push_back(i.second);
    }
    sort(c.begin(),c.end(),greater<int>());
    for(auto i:c){
        cout<<i<<" ";
    }
}

发表于 2022-03-07 21:34:45 回复(0)
Python3
class dice():
    def __init__(self, a):
        self.a=a
    def switch_out(self,i,j):
        if i!=j:
            self.a[2*i], self.a[2*i+1], self.a[2*j], self.a[2*j+1] = \
            self.a[2*j], self.a[2*j+1], self.a[2*i+1], self.a[2*i]
    def switch_in(self,i):
        if self.a[2*i]>self.a[2*i+1]:
            self.a[2*i], self.a[2*i+1] = self.a[2*i+1], self.a[2*i]
            self.a[2*i+2], self.a[2*i+3] = self.a[2*i+3], self.a[2*i+2]
    def tidy(self):
        i1=self.a.index(1)//2
        self.switch_out(0, i1)
        self.switch_in(0)
        i2=self.a.index(min(self.a[2:]))//2
        self.switch_out(1, i2)
        self.switch_in(1)
        return tuple(self.a)
n=int(input())
dc={}
for i in range(n):
    nd=dice(list(map(int, input().split()))).tidy()
    dc[nd]=dc.get(nd, 0)+1
print(len(dc.keys()))
for v in sorted(dc.values(), reverse=True):
    print(v, end=" ")


发表于 2021-10-29 07:48:42 回复(0)

思路就是枚举,具体来讲,按123456为初始,写出24种骰子六个面可能出现的排列情况(固定一个面作为前面的前提下只有4种情况,所以一共是24种可能性),然后就自然成为了映射矩阵。时间复杂度O(N2),其实是24*6*N*N,1000的数据量显然可以接受。
#include<iostream> #include<vector> #include<algorithm> using namespace std;   int a[24][6] = {     {1,2,3,4,5,6},     {4,3,1,2,5,6},     {2,1,4,3,5,6},     {3,4,2,1,5,6},           {1,2,4,3,6,5},     {3,4,1,2,6,5},     {2,1,3,4,6,5},     {4,3,2,1,6,5},           {1,2,6,5,3,4},     {5,6,1,2,3,4},     {2,1,5,6,3,4},     {6,5,2,1,3,4},           {1,2,5,6,4,3},     {6,5,1,2,4,3},     {2,1,6,5,4,3},     {5,6,2,1,4,3},           {6,5,3,4,1,2},     {4,3,6,5,1,2},     {5,6,4,3,1,2},     {3,4,5,6,1,2},           {5,6,3,4,2,1},     {4,3,5,6,2,1},     {6,5,4,3,2,1},     {3,4,6,5,2,1} };   int shai[6], tmp[6];   vector<int> cnt; int out[1010][6];   bool check(int a[6], int b[6]) {     int flag = 1;     for(int k = 0; k < 6; k++)     {         if(a[k] != b[k])         {             flag = 0;             break;         }     }     return flag; }   int main() {     int N;     cin >> N;     for(int i = 0; i < N; i++)     {         for(int j = 0; j < 6; j++)             cin >> shai[j];         int flag = 0;         for(int c = 0; c < cnt.size(); c++)         {             // 和每一个做对比             // 有24种可能             for(int j = 0; j < 24; j++)             {                 for(int k = 0; k < 6; k++)                 {                     tmp[k] = shai[a[j][k] - 1];                 }                                   if(check(out[c], tmp))                 {                     cnt[c]++;                     flag = 1;                     break;                 }             }             if(flag)                 break;         }         if(flag == 0)         {             for(int k = 0; k < 6; k++)                 out[cnt.size()][k] = shai[k];             cnt.push_back(1);         }     }           sort(cnt.begin(), cnt.end());     cout << cnt.size() << endl;     for(int i = cnt.size() - 1; i >= 0; i--)         cout << cnt[i] << ' '; }

编辑于 2021-08-09 01:06:13 回复(0)
不会做,硬模拟,把最小的放在上面,然后把剩余四个面中最小的放在后面,然后编码
from collections import *
N = int(input())
_d = defaultdict(int)
for l in range(N):
    tou = input().split()
    for i in range(6):
        tou[i] = int(tou[i])
    # 旋转骰子
    # 上0、下1、左2、右3、前4、后5
    high ,low ,left ,right ,front ,back = 0,1,2,3,4,5
    whereis1 = tou.index(1)
    if whereis1 == low:# 1在下面
        tou[high], tou[low] ,tou[left] , tou[right] = tou[low], tou[high] ,tou[right] , tou[left]
    elif whereis1 == left: # 1在左边
        tou[high], tou[low] ,tou[left] , tou[right] = tou[left], tou[right], tou[low], tou[high]
    elif whereis1 == right:#右边
        tou[high], tou[low] ,tou[left] , tou[right] = tou[right], tou[left], tou[high] , tou[low]
    elif whereis1 == front:
        tou[high], tou[low] , tou[front], tou[back] = tou[front], tou[back], tou[low],tou[high]
    elif whereis1 == back:
        tou[high], tou[low] , tou[front], tou[back] = tou[back],tou[front],tou[high],tou[low]
    _str = str(low)#让1在最上面了
    #左0、右1、前2、后3
    left, right, front ,back = 0,1,2,3
    tou = tou[2:]
    whereismin = tou.index(min(tou))
    # 让min在左边
    if whereismin == right:
        tou[left] , tou[right], tou[front], tou[back] = tou[right], tou[left], tou[back], tou[front]
    elif whereismin == front:
        tou[left] , tou[right], tou[front], tou[back] = tou[front], tou[back], tou[right], tou[left]
    elif whereismin == back:
        tou[left] , tou[right], tou[front], tou[back] = tou[back], tou[front], tou[left], tou[right]
    _str += str(tou[left])+str(tou[front])+str(tou[right])+str(tou[back])
    _d[_str]+=1
print(len(_d))
A= list(_d.values())
A.sort()
A = A[::-1]
for i in range(len(A)):
    print(A[i],end=" ")

发表于 2021-08-07 20:34:59 回复(0)

并查集

#include <bits/stdc++.h>
using namespace std;
int n;
vector<int> fa, sz;
int find(int x)
{
    return x == fa[x] ? fa[x] : (fa[x] = find(fa[x]));
}
bool merge(int x, int y)
{
    x = find(x), y = find(y);
    if (x == y)
    {
        return false;
    }
    if (sz[x] < sz[y])
    {
        swap(x, y);
    }
    fa[y] = x;
    sz[x] += sz[y];
    return true;
}
int main()
{
    cin >> n;
    vector<vector<int>> S(n, vector<int>(6));
    fa.resize(n), sz.resize(n, 1);
    iota(fa.begin(), fa.end(), 0);
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < 6; ++j)
        {
            cin >> S[i][j];
        }
    }
    auto f = [&](int i) -> vector<int>
    {
        if (S[i][0] == 1)
        {
            return vector<int>{S[i][5], S[i][3], S[i][4], S[i][2]};
        }
        else if (S[i][1] == 1)
        {
            return vector<int>{S[i][4], S[i][3], S[i][5], S[i][2]};
        }
        else if (S[i][2] == 1)
        {
            return vector<int>{S[i][0], S[i][4], S[i][1], S[i][5]};
        }
        else if (S[i][3] == 1)
        {
            return vector<int>{S[i][0], S[i][5], S[i][1], S[i][4]};
        }
        else if (S[i][4] == 1)
        {
            return vector<int>{S[i][0], S[i][3], S[i][1], S[i][2]};
        }
        return vector<int>{S[i][0], S[i][2], S[i][1], S[i][3]};
    };
    auto alike = [&](int i, int j) -> bool
    {
        auto a = f(i), b = f(j);
        for (int ii = 0; ii < 4; ++ii)
        {
            for (int jj = 0; jj < 4; ++jj)
            {
                if (a[ii] == b[jj])
                {
                    for (int k = 0; k < 4; ++k)
                    {
                        if (a[(ii + k) % 4] != b[(jj + k) % 4])
                        {
                            return false;
                        }
                    }
                    return true;
                }
            }
        }
        return false;
    };
    for (int i = 0; i < n; ++i)
    {
        for (int j = i + 1; j < n; ++j)
        {
            if (alike(i, j))
            {
                merge(i, j);
            }
        }
    }
    vector<int> T;
    for (int i = 0; i < n; ++i)
    {
        if (i == fa[i])
        {
            T.emplace_back(sz[i]);
        }
    }
    sort(T.begin(), T.end(), greater<>());
    int m = T.size();
    cout << m << '\n';
    for (int i = 0; i < m; ++i)
    {
        cout << T[i] << " \n"[i == m - 1];
    }
    return 0;
}
发表于 2021-05-12 19:02:19 回复(0)