• 角谷猜想


    题目描述 Description

    所谓角谷猜想,即给定一个正整数 n,对 n 反复进行下列两种变换:
    1)如果n是偶数,就除以2;
    2)如果n是奇数,就乘以3加1。
    最后的结果总是1。

    我们把从 n 变换到 1 所需要进行的变换次数称做 n 的变换长度,如数字 7 的变换为:

    7-22-11-34-17-52-26-13-40-20-10-5-16-8-4-2-1

    共进行了 16 次变换,因而 7 的变换长度为 16。

    Wish 现在对一个给定区间内的最长变换长度比较感兴趣,但是手算起来计算量太大,于是他又找到了参加信息学竞赛的你,你可以帮助他吗?

    输入描述 Input Description

    每个测试点包含多组数据,第一行一个数 t,表示数据个数。
    第二行至第 t+1 行,每行两个数 a、b,表示求 a 和 b 之间数(包含 a、b)的最长变换长度。


    输出描述 Output Description

    输出格式
    t 行,每行输出对应输入数据的各个区间的最长变换长度。

    样例输入 Sample Input

    2
    1 7
    9 20

    样例输出 Sample Output

    16
    20

    数据范围及提示 Data Size & Hint

    数据范围
    1 <= t <= 100
    1 <= a, b <= 10^8
    区间长度不超过 10^5

    任何一个大于一的自然数,如果是奇数,则乘以三再加一;如果是偶数,则除以二;得出的结果继续按照前面的规则进行运算,最后必定得到一。题目已知这个条件是成立的,所以只要模拟这个过程就行了,循环跳出的条件是“最后得到一”。

    记忆化搜索

    一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态。
    更重要的是搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多。
    记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来,
    以后再次遇到这个状态的时候,就不必重新求解了。
    这种方法综合了搜索和动态规划两方面的优点,因而还是很有实用价值的。
    记忆化搜索的实质是动态规划,效率也和动态规划接近,形式是搜索,简单直观,代码也容易编写,不需要进行什么拓扑排序了。
    可以归纳为:记忆化搜索=搜索的形式+动态规划的思想
    对于状态的存储,可用数组num[a] [b][c][d],其中a为还剩几个,b为找到了哪几个,c为找到的最后一个数,d表示是否已经出现1,4相连的两数。
    这样不需要任何其他的优化,程序就能0ms得到AC.
    #include <cstdio>
    #include <algorithm>
    #define max(x, y) ((x) > (y) ? (x) : (y))
    
    const int MAXN = 1e8 + 0x1;
    
    int t, a, b;
    int s, dp[MAXN];
    
    int solve(long long x) {
    	if (x == 1) return 0;
    	
    	if (x % 2) return solve(x * 3 + 1) + 1;
    	if (!(x % 2)) return solve(x / 2) + 1;
    }
    
    void dfs(int x) {
    	if (x == b + 1) return;
    	s = max(s, dp[x]);
    	dfs(x + 1);
    }
    
    int main() {
    	scanf("%d", &t);
    
    	while (t--) {
    		scanf("%d%d", &a, &b);
    		if (a > b) std::swap(a, b);
    		for (int i = a; i <= b; i++) dp[i] = (dp[i] ? dp[i] : solve(i));
    		s = 0;
    		dfs(a);
    		printf("%d
    ", s);
    	}
    	return 0;
    }

    #include<stdio.h>
    int main()
    {
    int n;
    scanf("%d",&n);
    while(n--)
    {
    int i;
    scanf("%d",&i);
    int temp=i;
    int count=0;
    while(temp-1)
    {
    if(temp%2==1)
    {
    count++;
    count==1?printf("%d",temp):printf(" %d",temp);//输出要注意,最后一个输出后面不能有空格
    temp=temp*3+1;
    }
    else if(temp%2==0) temp=temp/2;
    }
    if(count==0) printf("No number can be output !");
    printf(" ");
    }
    return 0;
    }

  • 相关阅读:
    C语言读写伯克利DB 4
    程序之美(转自知乎)
    C语言读写伯克利DB 3
    ON DUPLICATE KEY UPDATE
    nanomsg:ZeroMQ作者用C语言新写的消息队列库
    新浪研发中心: Berkeley DB 使用经验总结
    [企业开源系列]后起之秀Facebook凭什么挑战互联网霸主Google?
    BZOJ1770:[USACO]lights 燈(高斯消元,DFS)
    BZOJ5293:[BJOI2018]求和(LCA,差分)
    BZOJ5301:[CQOI2018]异或序列(莫队)
  • 原文地址:https://www.cnblogs.com/D-AngeloRussell/p/7234382.html
Copyright © 2020-2023  润新知