2016四平方和(枚举优化),斐波拉契数列的迭代算法,20省1-Jb4- 分配口罩(dfs、dp)

16省8-四平方和


四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。

比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)

对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法

程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开。

例子
输入
5

输出
0 0 1 2

输入
12

输出
0 2 2 2

输入
773535

输出
1 1 267 838

题目限制
单输出时间限制< 1s
峰值内存消耗 < 256M
CPU消耗 < 3000ms
枚举暴力但会超时,75分代码

#include <bits/stdc++.h>

using namespace std;


int main()
{  int i,j,k,l;
   int n;
   cin>>n;
   for(i=0;i*i<n;i++){
    for(j=0;j*j<n;j++){
        for(k=0;k*k<n;k++){
            for(l=0;l*l<n;l++){
               if(n==i*i+j*j+k*k+l*l) {
                printf("%d %d %d %d\n",i,j,k,l);
                return 0;
               }



            }

        }
    }
   }

    return 0;
}

优化,100分代码

#include<bits/stdc++.h>
using namespace std;
int n;
map<int,int>cache;
int main(){
    cin>>n;
    for(int c=0;c*c<=n/2;c++){
        for(int d=c;c*c+d*d<=n;d++){
                if(cache.find(c*c+d*d)==cache.end())//找不着的时候就存进去,已经存在就不用存进去
            cache[c*c+d*d]=c;
        }

    }
    for(int a=0;a*a<=n/4;a++){
        for(int b=a;a*a+b*b<=n/2;b++){
            if(cache.find(n-a*a-b*b)!=cache.end()){//找得到
                int c=cache[n-a*a-b*b];
                int d=int(sqrt(n-a*a-b*b-c*c));
                printf("%d %d %d %d",a,b,c,d);
                return 0;
            }
        }
    }

return 0;}

不太懂map<int,int>cache
参考博客里面的一些map相关的函数可以学起来记住。
下面这里说出了map的功能

2、map的功能
自动建立Key - value的对应。key和value可以是任意你需要的类型。
根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多
查找10次,1,000,000个记录,最多查找20次。
快速插入Key - Value记录。
快速删除记录
根据Key修改value记录。
遍历所有记录。

有点类似python里的字典

斐波拉契数列,迭代算法和递归算法


斐波那契数列:1、1、2、3、5、8、13…

使用迭代算法和递归算法都可以实现斐波那契数列,输出数列中的第N项,但是由于递归算法在计算时存在着大量的重复计算,所以在N值很大时,可能会造成内存的溢出,以及计算时间较长的情况出现,在使用迭代算法的情况下同样可以实现计算斐波那契数列第N项的功能,代码示例如下
递归(recursion)算法:

#include<bits/stdc++.h>
using namespace std;
int fibnace(int n){
    if(n==0) return 0;
    if(n==1) return 1;
    else return fibnace(n-1)+fibnace(n-2);

}
int main(){
    cout<<fibnace(40)<<endl;

return 0;}

迭代(iteratin)算法:

#include<bits/stdc++.h>
using namespace std;
int fibonacciteration(int num){
     if(num==0) return 0;
     if(num==1||num==2) return 1;
     int first=1,second=1,third=0;
     for(int i=3;i<=num;i++){
        third=first+second;
        first=second;
        second=third;
     }
     return third;


}
int main(){
  cout<<fibonacciteration(40)<<endl;

}

比较:当n小的时候,递归和迭代时间差异基本不大,当n大的时候,时间差异明显较大,列入当n=40的时候,递归就明显变得很慢。所以在n大时,迭代算法时间上较快。

20省1-Jb5- 斐波那契数列最大公约数


【问题描述】
斐波那契数列满足 F1 = F2 = 1,从 F3 开始有 Fn = Fn−1 +Fn−2。
请你计算 GCD(F2020,F520),其中 GCD(A,B) 表示 A 和 B 的最大公约数。

【输入】
没有输入。

【输出】
输出一个整数。
思路
数学中有一个重要的定理 gcd(f(n),f(m))=f(gcd(n,m))可以简化该题

#include<bits/stdc++.h>
using namespace std;
int fibonacciteration(int num){
     if(num==0) return 0;
     if(num==1||num==2) return 1;
     int first=1,second=1,third=0;
     for(int i=3;i<=num;i++){
        third=first+second;
        first=second;
        second=third;
     }
     return third;


}
int gcd(int i,int j){
    return (!j)?i:gcd(j,i%j);
}
int main(){
  cout<<fibonacciteration(gcd(2020,520))<<endl;

}

20省1-Jb4- 分配口罩

【问题描述】
某市市长获得了若干批口罩,每一批口罩的数目如下:

9090400
8499400
5926800
8547000
4958200
4422600
5751200
4175600
6309600
5865200
6604400
4635000
10663400
8087200
4554000

现在市长要把口罩分配给市内的2所医院。
由于物流限制,每一批口罩只能全部分配给其中一家医院。
市长希望2所医院获得的口罩总数之差越小越好。
请你计算这个差最小是多少?

【输入】
没有输入。

【输出】
输出一个整数。
思路
我当时审题有点错误,我以为是每家医院从这15个里面拿出一个送,也就是我当时求了15个数两俩差最小,结果是错的。
想也知道,按照蓝桥杯传统习俗,肯定是暴力之类可以解决大部分题目。
题解是,15批全部发送给2个医院,然后求最小差。
解题
这个题就是把数组分成两个部分,求两部分和最小值的包装版本,可以用暴力dfs也可以dp(0-1背包作背包容量为sum/2的dp),结果填空且只有15个数,直接暴力搜即可。
dfs

#include<bits/stdc++.h>
using namespace std;
long long mask[15]={9090400,8499400,5926800,8547000,4958200,4422600,5751200,4175600,6309600,5865200,6604400,4635000,10663400,8087200,4554000};
long long sum=0;
long long minn=0xffffff;
int dfs(int x,long long now){
    if(x>=15){
        minn=min(minn,abs(sum-2*now));
        return 0;
    }
    dfs(x+1,now+mask[x]);
    dfs(x+1,now);
}
int main(){
    int i;
    for(i=0;i<15;i++){
        sum+=mask[i];
    }
    dfs(0,0);
    printf("%lld",minn);


return 0;}

dp

public class Main {
    public static void main(String[] args) {
        int sum = 0 , su = 0;
        int[] nums = {0, 9090400, 8499400, 5926800, 8547000, 4958200,
                4422600, 5751200, 4175600, 6309600, 5865200, 6604400, 4635000,
                10663400, 8087200, 4554000};

        for (int i = 0; i < nums.length; i++) {
            sum = sum + nums[i];
        }
        su = sum / 2;
        int[] dp = new int[su+1];
        for (int i = 1; i < nums.length; i++) {
            for (int j = su; j >= nums[i]; j--) {
                dp[j] = Math.max(dp[j] , dp[j-nums[i]] + nums[i]);
            }
        }
        System.out.println(2 * (su - dp[su]));
    }
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值