Blue Bridge カップループ カウンティング (状態圧縮、動的プログラミング)

トピックの説明

ブルーブリッジアカデミー by 21 2121の教棟で構成されており、教棟番号は11 111121 21212つの教棟aaabbb​,当 a a abbbが互いに素なとき、aaabbb間には直接接続されたコリドーがあり、両方向にアクセスできます。それ以外の場合は、直接接続されたコリドーはありません。

シャオランは現在、最初の教育棟にいます。各教育棟を 1 回だけ訪問し、最後に最初の教育棟に戻りたいと考えています (つまり、ハミルトン ループに乗ります)。彼にはさまざまな訪問計画が何通りありますか?

2 つのアクセス スキームの違いは、特定のiiがあることを意味します。i、シャオランは 2 つのアクセス方法で教育棟を訪問しました。iiその後、さまざまな教育施設を訪問しました

ヒント: この問題を解決するには、コンピューター プログラミングを使用することをお勧めします。

回答の提出

結果を空欄に記入する問題です。結果を計算して提出するだけです。この質問の結果は整数です。この整数は回答を送信するときにのみ入力してください。冗長な内容を入力すると得点は得られません。

動作限界

最大実行時間: 1 秒
最大実行メモリ: 128M

アイデアとリファレンスコード

この問題は動的計画法を使用して解決できます。

1 、 2 、 . . . 、 21 1,2,...,21 を使用します。1 2 ... 21 は特定の建物を意味し、完全な集合A = { 1 , 2 , . . . , 21 } A = \{1,2,...,21\} を={ 1 2 ... 21 }状態をSV , l S_{V,\ l}SV   lサブセットVV が訪問されたことを示しますすべてのパスはVにあり(各ポイントは 1 回だけ訪問されます)、最後の着地点はlllにおける実行可能な解の数V ⊆ AV \subseteq AVAl ∈ V l \in VV. _ つまり、動的計画法方程式
SV , l = ∑ a ∈ V と a , l 互いに素 SV − { l } , a S { 1 } , 1 = 1 S_{V,\ l} = \sum_{a\ があります。 V と a,l は互いに素} S_{V- \{l\},\ a} \\S_{\{1\},\ 1 }= 1SV   l=a Va lは互いに素ですSV { l }   aS{ 1 }   1=1

最終的な答えは、∑ i = 2 21 SA , i \sum_{i=2}^{21}{S_{A,\ i}}です。i = 221S 建物が 21 個しかないため、実装ではパス セットVV が設定されていますV は、完全な 21 の建物を通過するなど、ビット セットを使用して1 つの変数に圧縮するだけで済みます。int渡されるパスは です0x1fffff

完全な実装は次のとおりです。

public class Main {
    
    
    static boolean[][] isConnected = new boolean[22][22];
    static final int MAXN = 0x1fffff;
    static long[][] counts = new long[MAXN + 1][22];

    static void init() {
    
    
        for (int i = 1; i <= 21; i++) {
    
    
            for (int j = i + 1; j <= 21; j++) {
    
    
                boolean flag = false;
                for (int k = 2; k <= i; k++) {
    
    
                    if (i % k == 0 && j % k == 0) {
    
    
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
    
    
                    isConnected[i][j] = isConnected[j][i] = true;
                }
            }
        }
    }

    static void debug() {
    
    
        for (int i = 1; i <= 21; i++) {
    
    
            for (int j = i + 1; j <= 21; j++) {
    
    
                if (isConnected[i][j])
                    System.out.printf("%d %d\n", i, j);
            }
        }
    }

    static void dp() {
    
    
        counts[1][1] = 1;
        for (int i = 1; i <= MAXN; i++) {
    
    
            for (int j = 1; j <= 21; j++) {
    
    
                if (((i >> (j - 1)) & 1) == 0)
                    continue;
                for (int k = 1; k <= 21; k++) {
    
    
                    if (((1 << (k - 1)) & i) != 0 || !isConnected[j][k])
                        continue;
                    counts[i | (1 << (k - 1))][k] += counts[i][j];
                }
            }
        }
    }

    static void printAnswer() {
    
    
        long cnt = 0;
        for (int i = 1; i <= 21; i++) {
    
    
            if (isConnected[i][1])
                cnt += counts[MAXN][i];
        }
        System.out.println(cnt);
    }

    public static void main(String[] args) {
    
    
        init();
//        debug();
        dp();
        printAnswer();
    }
}

おすすめ

転載: blog.csdn.net/weixin_46655675/article/details/131055316