トピックの説明
ブルーブリッジアカデミー by 21 2121の教棟で構成されており、教棟番号は11 1111~21 2121.2つの教棟aaaとbbb,当 a a aとbbbが互いに素なとき、aaaとbbb間には直接接続されたコリドーがあり、両方向にアクセスできます。それ以外の場合は、直接接続されたコリドーはありません。
シャオランは現在、最初の教育棟にいます。各教育棟を 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 AV⊆A,l ∈ V l \in V私∈V. _ つまり、動的計画法方程式
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 ∈ Vとa 、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();
}
}