UVA 10601 Cubes (組合數學 + ploya計數)

題意:

有12根等長火柴,每根火柴的顏色是6種顏色中的一種,輸入每根火柴的顏色,求構成的立方體有多少種,旋轉後完全相同的立方體視爲相同。

思路:

一直以來只理解了ploya的皮毛。。所以看見這種題,可以求出置換種類,循環節個數,長度。。但依然不會計算。
一個立方體的旋轉置換有24種,分別是:

  • 靜止不動(包含1種置換),循環節有12個,每個長度爲1;

  • 以對頂點的連線爲軸,旋轉120°,240°(包含4 × 2 = 8種置換),兩種旋轉角度的循環節均有4個,長度爲3;

  • 以對邊中點的連線爲軸,旋轉180°(包含6 × 1 = 6種置換),這種置換有兩種長度的循環節,分別是軸所在對邊構成的兩個長度爲1的循環節,以及其他邊構成的5個長度爲2的循環節;

  • 以對面中心的連線爲軸,旋轉90°,180°,270°(包含3 × 3 = 9種置換),旋轉90°與270°的置換有3個長度爲4的循環節,旋轉180°的置換有6個長度爲2的循環節。

知道置換種類與對應的循環節個數與長度後,就可以用組合計數的方式來統計每種置換的方案數,計算方式就是把12根火柴分成每一種置換的各個循環,如果不能分,即12不能整除循環節長度則該置換方案數爲0.
處理有不同長度循環節的置換,可以將其拆分開來統計。

(看到有人用6維揹包做,驚爲天人。。

代碼:

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

typedef unsigned long long lint ;
lint C[13][13] ;
int cnt[7], a[7] ;
void init()
{
    C[0][0] = 1;
    for (int i = 1; i < 13; i++) {
        C[i][0] = 1;
        for (int j = 1; j < i + 1; j++) {
            C[i][j] = C[i-1][j] + C[i-1][j-1] ; ;
        }
    }
}

lint count(int k) 
{
    int n = 0 ;
    for (int i = 0; i < 6; i++) {
        if (cnt[i] % k == 0) {
            cnt[i] /= k ;
            n += cnt[i];
        }
        else return 0 ;
    }
    lint ret = 1 ;
    for (int i = 0; i < 6; i++) {
        ret *= C[n][cnt[i]] ;
        n -= cnt[i] ;
    }
    return ret ;
}
lint still()
{
    memcpy(cnt, a, sizeof a) ;
    return count(1) ;
}
lint point()
{
    memcpy(cnt, a, sizeof a) ;
    return 8 * count(3) ;
}
lint edge()
{
    lint ret = 0 ;
    for (int i = 0; i < 6; i++)
        for (int j = 0; j < 6; j++) {
            if (!a[i] || !a[j]) continue ;
            memcpy(cnt, a, sizeof a) ;
            cnt[i]-- ; cnt[j]-- ;
            ret += 6 * count(2) ;
        }
    return ret ;
}
lint plane()
{
    lint ret = 0 ;
    memcpy(cnt, a, sizeof a) ;
    ret += 3 * count(2) ;
    memcpy(cnt, a, sizeof a) ;
    ret += 6 * count(4) ;
    return ret ;
}
void work()
{
    lint ans = 0 ;
    ans += still() ;
    ans += point() ;
    ans += edge() ;
    ans += plane() ;
    cout << ans / 24 << endl ;
}
int main()
{
    init() ;
    int t ; cin >> t ;
    while (t-- ){
        memset(a, 0, sizeof a) ;
        for (int i = 0; i < 12; i++) {
            int col ; scanf("%d", &col) ;
            a[col-1]++ ;
        }
        work() ;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章