C++思考练习(一)

看到了这道数学题,那么我们可以思考如何将这道题与程序联系起来。

(一)题目1

使用一个整数数组来初始化这样的一个加减封闭性集合,再输入一个整数x,判断整数x是否在生成的这个集合中。

解法:我们发现如果这个集合中存在1,则集合就是整数集。如果这个集合中存在元素x,则kx一定也在这个集合中。根据裴蜀定理,这个数组的元素进行有限次加减一定可以得到它们的最大公因数;而它们的最大公因数如果在这其中,这些元素也在集合中。因此,这道题就变成了求解数组的最大公因数,再判断整数x是否可以整除x。

我们有两种处理方法:

1.暴力解法

直接声明一个集合,根据题目中的描述进行处理。

#include <iostream>
#include <set>
#include <vector>
#include <queue>
using namespace std;

int main()
{
    int n;
    cin>>n;
    vector<int> v(n);
    for(int i=0; i<n; i++)
    {
        cin>>v[i];
    }
    set<int> s(v.begin(), v.end());
    int x;
    cin>>x;
    if(s.find(x)!=s.end())
    {
        cout<<"YES"<<endl;
        return 0;
    }
    queue<int> q;
    for(int i=0; i<n; i++)
    {
        q.push(v[i]);
    }
    set<int> visited;
    for(int i=0; i<n; i++)
    {
        visited.insert(v[i]);
    }
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        for(int i=0;i<n;i++)
        {
            int l=t-v[i];
            int r=t+v[i];
            if(l==x||r==x)
            {
                cout<<"YES"<<endl;
                return 0;
            }
            if(visited.find(l)==visited.end())
            {
                q.push(l);
                visited.insert(l);
            }
            if(visited.find(r)==visited.end())
            {
                q.push(r);
                visited.insert(r);
            }
        }
    }
    cout<<"NO"<<endl;
    return 0;
}

最坏的情况下的时间复杂度是O(2^{n})

2.辗转相除法

使用辗转相除法求解最大公约数。

#include <iostream>
#include <vector>

using namespace std;

int gcd(int x, int y)
{
    if(y==0)
    {
        return x;
    }
    return gcd(y, x%y);
}

int main()
{
    int n;
    cin>>n;
    vector<int> v(n);
    for(int i=0; i<n; i++)
    {
        cin>>v[i];
    }
    int x;
    cin>>x;
    int res=v[0];
    for(int i=1;i<n;i++)
    {
        res=gcd(res,v[i]);
    }
    if(x%res==0)
    {
        cout<<"YES"<<endl;
    }
    else
    {
        cout<<"NO"<<endl;
    }
    return 0;
}

时间复杂度接近于O(n)。 

(二)题目2

如果将取值范围从整数扩展到浮点类型,如何处理?

解法:我们考虑是否可以使用相似的方法,但我们发现这是小数,于是我们可以将它们转化为整数。将这多个浮点数的小数点同时右移,直到所有数据都变为整数,此时就可以使用上述的判断方法了。

1.暴力解法

我们需要考虑精度问题,我们可以将输入数据的小数点同时向右移直到全部都变为整数,再使用整数方法进行处理。

2.辗转相除法

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

int gcd(int x, int y)
{
    if(y==0)
    {
        return x;
    }
    return gcd(y, x%y);
}

int main()
{
    int n;
    cin>>n;
    string s;
    vector<int> v1(n,0);
    int len=0;
    int t;
    vector<int> l(n);//每个的长度
    for(int i=0; i<n; i++)
    {
        t=0;
        cin>>s;
        for(int j=0;j<s.size();j++)
        {
            if(s[j]=='.') 
            {
                t=j;
                continue;
            }
            v1[i]=v1[i]*10+s[j]-'0';
        }
        l[i]=s.size()-1-t;
        len=max(len,l[i]);
    }
    cin>>s;
    int x=0;
    int xl=0;
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='.')
        {
            t=i;
            continue;
        }
        x=x*10+s[i]-'0';
    }
    xl=s.size()-1-t;
    vector<int> v2(n);
    for(int i=0; i<n; i++)
    {
        v2[i]=v1[i]*pow(10,len-l[i]);
    }
    int res=v2[0];
    for(int i=1;i<n;i++)
    {
        res=gcd(res,v2[i]);
    }
    if(xl<=len)
    {
        x=x*pow(10,len-xl);
        if(x%res==0)
        cout<<"YES"<<endl;
        else
        cout<<"NO"<<endl;
    }
    else
    {
        cout<<"NO"<<endl;
    }
    return 0;
}

还使用了字符串方法防止了浮点精度的影响。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值