c语言——完全平方数问题

1.题目描述

完全平方数是一个整数,其值等于另一个整数的平方;例如,1、4、9 和 16 都是完全平方数,而了和 11 不是

2.输入和输出

输入一个整数n,1<=n<=1000

输出和为 n的完全平方数的最少数量

3.输入样例

13

4.输出样例

2

5.解题思路

(1) BFS (广度优先探索)解法

BFS 全称是 Breadth First Search,中文名是宽度优先搜索,也叫广度优先搜索。

是图上最基础、最重要的搜索算法之一。

所谓宽度优先。就是每次都尝试访问同一层的节点。 如果同一层都访问完了,再访问下一层。

这样做的结果是,BFS 算法找到的路径是从起点开始的 最短 合法路径。换言之,这条路径所包含的边数最小。

在 BFS 结束时,每个节点都是通过从起点到该点的最短路径访问的。

算法过程可以看做是图上火苗传播的过程:最开始只有起点着火了,在每一时刻,有火的节点都向它相邻的所有节点传播火苗。


以上资料来自于BFS(图论) - OI Wiki (oi-wiki.org)

深度理解:(c语言实现)算法笔记之bfs及pta习题

对于此题:可以把所有的数想成一颗多叉树,n为根节点,每个数减去所有可能的平方数得到的差值作为它的子节点,如此下去,最先为0的数所在的层数即我们所需要的的答案。但是要处理超时的问题,除去重复的情况,这里采用一个boolean数组去存

bool类型数组

1.导入

存放于<stdbool.h>头文件中,开头加#include <stdbool.h>引用

2.定义

int N = 5;

bool flag [N];

3.初始化

虽然bool类型默认值是0,但是仍要初始化。

在这里插入图片描述

(2)完全背包问题

这题可以把n当做背包的总容量,把完全平方数当做物品的重量,题目就转换为,用最少的物品放 满背包,物品可以重复选择。这就是一个典型的完全背包问题了。

  • 定义dp[i] 表示当背包容量为i时,放满背包的最少物品数量。
  • 对于任意容量i,dp[i]初始值为i,即最坏的情况,装i个重量为1 * 1的物品。

关于头文件<limits.h>  

#include <limits.h> 是 C 语言中的标准库头文件之一,它定义了各种整数类型的限制和属性。通过包含该头文件,可以使用其中定义的常量和宏来获取与整数类型相关的一些信息。

  • 整数类型的整数类型和最大值(以补码表示):

    • INT_MININT_MAXint 类型的最小值和最大值。
    • LONG_MINLONG_MAXlong 类型的最小值和最大值。
    • LLONG_MINLLONG_MAXlong long 类型的最小值和最大值。

深入学习:1.【c语言】#include <limits.h>

                  2.  C语言limits.h

  • 如果当前重量为num的物品能够装入背包,则dp[i] = dp[i - num] +1,如果不能装入背包,则dp[i] = dp[i]。所以dp[i] = min(dp[i - num] + 1, dp[i])
  • 最终结果为dp[n]

(3) 数学问题

    利用四平方定理:任何一个正整数都可以表示成不超过4个整数的平方之和

    证明见Lagrange 四平方定理

  • 所以答案只能是[1, 2, 3, 4]中的一个。
  • 如果一个数可以表示成4个整数的平方和,那么这个数一定满足公式 n = (4^a)*(8b+7)
  • 如果一个是本身就是完全平方数,那么答案就是1。
  • 如果答案是2,那么n = a ^ 2 + b ^ 2,那么可以枚举a进行验证
  • 剩下的答案就是3 

 6.代码

(1) BFS (广度优先探索)解法

#include <stdio.h>  
#include <stdlib.h>  
#include <stdbool.h>  
  
#define MAX_N 1000  
  
int numSquares(int n);  
  
int main() {  
    int n ; 
    scanf("%d",&n);  
    int res = numSquares(n);  
    printf("%d\n", res);  
    return 0;  
}  
  
int numSquares(int n) {  
    int queue[MAX_N];  
    int size = 1; // 初始化队列大小为1  
    queue[0] = n; // 将n入队  
    int res = 0; // 记录结果  
    bool visited[MAX_N] = {false}; // 记录已经访问过的数  
    visited[n] = true; // 将n标记为已访问过  
  
    while (size > 0) { // 当队列非空时  
        int i;  
        for (i = 0; i < size; i++) { // 遍历当前队列中的元素  
            int num = queue[i]; // 取出当前元素  
            if (num == 0) { // 如果当前元素为0,说明找到了解,返回结果  
                return res;  
            }  
            for (int j = 1; j * j <= num; j++) { // 对于每个j,如果num-j没有被访问过,并且num-j是合法的值(小于等于n)  
                if (!visited[num - j] && num - j <= n) { // 如果num-j满足条件,将其入队,并标记为已访问过  
                    queue[size++] = num - j;  
                    visited[num - j] = true;  
                }  
            }  
        }  
        size = 0; // 将队列清空,准备下一轮的搜索  
        res++; // 增加结果的值  
    }  
    return -1; // 如果队列为空,说明没有找到解,返回-1  
}

(2)完全背包问题

#include <stdio.h>  
#include <stdlib.h>  
#include <limits.h>  
  
int min(int a, int b) {  
    return a < b ? a : b;  
}  
  
int numSquares(int n) {  
    int *dp = (int *)malloc(sizeof(int) * (n + 1));  
    int i, j;  
  
    for (i = 0; i <= n; i++) {  
        dp[i] = INT_MAX; // 初始化为最大值  
    }  
  
    dp[0] = 0; // 0个物品装入背包,所需价值为0  
  
    for (i = 1; i <= n; i++) {  
        for (j = 1; j * j <= i; j++) {  
            dp[i] = min(dp[i], dp[i - (j * j)] + 1);  
        }  
    }  
  
    int result = dp[n];  
    free(dp); // 释放内存空间  
    return result;  
}  
  
int main() {  
    int n ; // 输入一个正整数n
    scanf("%d",&n);  
    int result = numSquares(n); // 计算最少需要多少个完全平方数来表示n  
    printf("%d\n", result); // 输出结果  
    return 0;  
}

(3)数学问题

#include <stdio.h>  
#include <math.h>  
  
int numSquares(int n) {  
    // 根据公式 n = (4^a)*(8b+7)缩小n  
    while (n % 4 == 0) {  
        n /= 4;  
    }  
    // 如果满足公式,则返回  
    if (n % 8 == 7) {  
        return 4;  
    }  
  
    // 判断缩小后的数是否可以由一个数的平方或者两个数的平方和组成  
    int a = 0;  
    while ((a * a) <= n) {  
        double b = sqrt(n - a * a);  
        if (a * a + b * b == n) {  
            if (a != 0 && b != 0) {  
                return 2;  
            } else {  
                return 1;  
            }  
        }  
        a++;  
    }  
    return 3;  
}  
  
int main() {  
    int n ; // 输入一个正整数n 
    scanf("%d",&n); 
    int result = numSquares(n); // 计算最少需要多少个完全平方数来表示n  
    printf("%d\n", result); // 输出结果  
    return 0;  
}

内容参考:完全平方数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值