uva 10601 Cubes(等价类计数,Burnside引理)

本文详细介绍了如何使用Burnside引理解决UVA10601立方体问题,该问题是计算利用12根不同颜色的棒子可以拼成多少种不同的正方体。文章通过具体的代码实现展示了如何计算在考虑空间位置变化的情况下不同正方体的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

uva 10601 Cubes(等价类计数,Burnside引理)

告诉你12根棒子的颜色,问一共能拼成多少个不同的正方体?

(通过改变空间位置变成相同的正方体,则视为同一种方案)

一看到这题感觉束手无策,即使你空间想象能力再好,恐怕也难以想出方案数。。

Burnside引理提供了一个良好的工具,下面就以此题为例详细介绍Burnside引理及其应用。


/*
    等价类计算问题,有力武器是Burnside引理:
    总方案数 = 置换的不动点数的平均值。
   (若一种方案s经过置换F后,任与原方案等价,则称s为F的一个不动点。)
*/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;

int a[6] , b[6] ;
LL C[15][15];
void calc_combin()
{
    C[0][0] = 1;
    for(int i=1;i<15;i++){
        C[i][0] = 1;
        for(int j=1;j<=i;j++)
            C[i][j] = C[i-1][j-1] + C[i-1][j];
    }
}
LL fixpoint(int m)  // 计算循环长度为m时的不动点个数
{  // 一种置换可以写成多个循环相乘的形式,只要每个循环内部颜色
    //相同即为不动点,否则不是  不动点 。
    int n = 0;
    LL ans = 1;
    for(int i=0;i<6;i++) {
        if(b[i] % m) return 0;
           // 循环内部必须颜色相同,故每种颜色的物品数量一定是m的整数倍。
        b[i] /= m;
        n += b[i];
    }
    /*
      每个循环看成一个位置,颜色相同的m个木棍看成一个物品。
      n个物品(总共6种,每种b[i]个)放在n个不同位置 ,有多少种方案?
    */
    for(int i=0;i<6;i++){
        ans *= C[n][b[i]] ;  // 从剩余n个位置中选b[i]个放这b[i]个物品。
        n -= b[i] ;
    }
    return ans;
}
#define COPY memcpy(b,a,sizeof(a))
LL solve(){
    LL ans = 0;
    // 先求不动点数的总和,总共有24中置换方法,下面依次列举。

    //① 静止不动,循环长度为1
    COPY;
    ans += fixpoint(1);

    //② 以两个相对的面的中心点的连线为轴(有3条这样的对称轴),
    //沿一方向旋转90° 、 180° 、270°
    COPY;
    ans += 3 * fixpoint(4) ; // 90° ,循环长度为4
    COPY;
    ans += 3 * fixpoint(2) ; // 180° ,转两次回到原位,即循环长度为2.
    COPY;
    ans += 3 * fixpoint(4) ; // 270° 。

    //③ 以两个相对的棱的中心点的连线为轴(有6条这样的对称轴),
    //沿一方向旋转180° , 这两条棱静止不动,不参与循环。
    for(int i=0;i<6;i++)   // 枚举两条静止的棱的颜色.
    for(int j=0;j<6;j++){
        COPY;
        if(--b[i]<0 || --b[j]<0) continue;
        ans += 6 * fixpoint(2); // 循环长度为2
    }

    // ④  以体对角线为轴(有4条) ,旋转120°、240° , 循环长度均为3.
    COPY ;
    ans += 8 * fixpoint(3);  // 120° 和 240° 各四种

    return ans / 24;  // 每种置换的不动点数的平均值。
}
int main()
{
    calc_combin();

    int T;
    scanf("%d",&T);
    while(T--){
        memset(a,0,sizeof(a));
        int x;
        for(int i=0;i<12;i++){
            scanf("%d",&x);
            a[x-1]++;
        }
        printf("%lld\n",solve());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值