《算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge。
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。
“ 冰雹猜想II” ,链接: http://oj.ecustacm.cn/problem.php?id=1744
题目描述
【题目描述】 冰雹猜想是指对于任意一个正整数,如果它是奇数,则对它乘3加1,如果是偶数,则除以2,最终会变成1,目前仍未找到反例。
例如数字6。按照上述规则可以变成3、10、5、16、8、4、2、1,经过8次变换。
现在给定数字n,求存在多少个数字变换n次得到1。。
【输入格式】 输入一个数字n(0≤n≤55)。
【输出格式】 输出一个数字表示答案。
【输入样例】
样例1
0
样例2
4
样例3
8
【输出样例】
样例1
1
样例2
1
样例3
4
题解
本题显然用倒推,有2种情况:(1)“除以2”的倒推,是“乘2”;(2)“乘3加1”的倒推,是“减1除以3”,需要注意,此时应该判断“减1除以3”能除尽,而且是奇数。
本题是路径问题,编码用DFS和BFS都行,DFS更简单一些。
【重点】 用BFS和DFS求解路径问题。
C++代码
由于每次倒推有2种情况,在代码中每次DFS时继续做2次DFS,所以变换次数ans是
O
(
2
n
)
O(2^n)
O(2n)复杂度的,需要用long long类型。
注意第6行是剪枝,如果倒推过程中又出现了1,说明这次倒推是无效的,直接返回。
#include<bits/stdc++.h>
using namespace std;
int n;
long long ans=0;
void dfs(long long x,long long cnt){
if(x==1 && cnt!=1) return; //又倒推回1,无效操作,不统计ans,直接返回
if(cnt == n+1){ //刚好n次,结束
ans++;
return;
}
dfs(2*x, cnt+1); //“除以2”的倒推:乘2
if((x-1)%3==0 && ((x-1)/3)%2==1) //(x-1)%3:能除尽,而且是奇数
dfs((x-1)/3, cnt+1); //“乘3加1”的倒推:减1除以3
}
int main(){
cin>>n;
dfs(1,1);
cout<<ans;
}
Java代码
import java.util.Scanner;
public class Main {
static int n;
static long ans = 0;
public static void dfs(long x, long cnt) {
if (cnt != 1 && x <= 1) return; //又倒推回1,无效操作,不统计ans,直接返回
if (cnt == n + 1) { //刚好n次,结束
ans++;
return;
}
dfs(2 * x, cnt + 1); //“除以2”的倒推:乘2
if ((x - 1) % 3 == 0 && ((x - 1) / 3) % 2 == 1) //(x-1)%3:能除尽,而且是奇数
dfs((x - 1) / 3, cnt + 1); //“乘3加1”的倒推:减1除以3
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
dfs(1, 1);
System.out.println(ans);
}
}
Python代码
n = int(input())
ans = 0
def dfs(x, cnt):
global ans
if cnt != 1 and x <= 1: return #又倒推回1,无效操作,不统计ans,直接返回
if cnt == n+1:
ans += 1
return
dfs(2*x, cnt+1) #“除以2”的倒推:乘2
if (x-1)%3 == 0 and ((x-1)//3)%2 == 1: # (x-1)%3:能除尽,而且是奇数
dfs((x-1)//3, cnt+1) # “乘3加1”的倒推:减1除以3
dfs(1,1)
print(ans)