题目描述
蓝桥学院由 21 栋教学楼组成,教学楼编号 1 到 21。对于两栋教学楼 a 和 b,当 a 和 b 互质时,a 和 b 之间有一条走廊直接相连,两个方向皆可通行,否则没有直接连接的走廊。
小蓝现在在第一栋教学楼,他想要访问每栋教学楼正好一次,最终回到第一栋教学楼(即走一条哈密尔顿回路),请问他有多少种不同的访问方案?
两个访问方案不同是指存在某个 i,小蓝在两个访问方法中访问完教学楼 i 后访问了不同的教学楼。
提示:建议使用计算机编程解决问题。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
题目分析
互质问题
写过了就不重复了,质数的其他实现
哈密尔顿回路
最简单好写的应该就是暴力遍历了,不过会有2^21次方案,估计得10多分钟才能算出来。
那么就想要记录和存储状态。
存储每一个楼层的状态可以使用:二进制计数,每一个位置1则为到达,0则为未曾到达。
因为这个是一个填空题,所以代码不需要按照他所给出的运行时间来。
具体实现:
首先计算1-21号楼的互通情况
[2.初始化dp]
进行算法递归
递归出口,查看是否已经到全部到达过(1号楼可以通往其他所有楼所以全部到达就可以了)
循环所有的可以通往的楼层
查看是否已经到达过
查看dp数组是否有答案(即当前状态下,该楼层完成任务的次数)
如果有则ans+答案
如果没有,则记录当前的ans
递归下一个
记录2者的ans插值,即是当前dp数组的值
建议结合代码食用
队列+dp数组+数组+填充 2189ms
static long ans = 0;
static long[][] dp=new long[1<<22][22];
static boolean[][] a = new boolean[22][22];
public static void main(String[] args) {
for (int i = 1; i < 22; i++)
for (int j = 1; j < 22; j++)
if (gcd(i,j) == 1)
a[i][j] = true;
for (long[] longs : dp) {
Arrays.fill(longs,-1);
}
dfs(1,1);
System.out.println(ans);
}
static void dfs(int state, int pre) {
if (state == (1 << 21) - 1){
ans++;
return;
}
Queue<Integer> q = new LinkedList<>();
for (int i = 1; i < 22; i++) {
if ((state >> (i-1) & 1) == 1 || !a[pre][i])
continue;
q.add(i);
}
long t;
for (Integer i : q) {
if (dp[state][i] != -1) {
ans += dp[state][i];
continue;
}
t = ans;
dfs(state + (1 << i-1), i);
dp[state][i] = ans - t;
}
}
集合arraylist+dp数组+填充1436ms
static long ans = 0;
static long[][] dp=new long[1<<22][22];
static ArrayList<Integer>[] a = new ArrayList[22];
public static void main(String[] args) {
for (int i = 0; i < 22; i++) {
a[i] = new ArrayList<>();
}
for (int i = 1; i < 21; i++) {
for (int j = i + 1; j <= 21; j++) {
if (gcd(i, j) == 1) {
a[i].add(j);
a[j].add(i);
}
}
}
for (long[] longs : dp) {
Arrays.fill(longs,-1);
}
dfs(1,1);
System.out.println(ans);
}
static void dfs(int state, int pre) {
if (state == (1 << 21) - 1){
ans++;
return;
}
ArrayList<Integer> list = a[pre];
if (list.size() == 0) return;
long t;
for (Integer i : list) {
if ((state >> (i-1) & 1) == 1)
continue;
if (dp[state][i] != -1) {
ans += dp[state][i];
continue;
}
t = ans;
dfs(state + (1 << i-1), i);
dp[state][i] = ans - t;
}
}
Map dp +arraylist 5596ms
static long ans = 0;
static Map<Integer,Long> dp = new HashMap<>();
static ArrayList<Integer>[] a = new ArrayList[22];
public static void main(String[] args) {
for (int i = 0; i < 22; i++) {
a[i] = new ArrayList<>();
}
for (int i = 1; i < 21; i++) {
for (int j = i + 1; j <= 21; j++) {
if (gcd(i, j) == 1) {
a[i].add(j);
a[j].add(i);
}
}
}
dfs(1,1);
System.out.println(ans);
}
static void dfs(int state, int pre) {
if (state == (1 << 21) - 1){
ans++;
return;
}
ArrayList<Integer> list = a[pre];
if (list.size() == 0) return;
long t;
int l = state*100;
for (Integer i : list) {
if ((state >> (i-1) & 1) == 1)
continue;
int z = l + i;
if (dp.containsKey(z)) {
ans += dp.get(z);
continue;
}
t = ans;
dfs(state + (1 << i-1), i);
dp.put(z,ans-t);
}
}