【算法题】神奇数

东东在一本古籍上看到有一种神奇数,如果能够将一个数的数字分成两组,其中一组数字的和等于另外一组数字的和,我们就将这个数称为神奇数。例如242就是神奇数,我们能够将这个数字分成两组,分别是{2,2}以及{4},给定区间[l,r],统计这个区间有多少个神奇数,请你来帮助他。

这里写图片描述


首先判断数组能否被平分,即数组分割问题,

dp[i][j] 表示数组前 i 个数字能否求和得到 j

dp[i][j]=dp[i1][j]||dp[i1][jarray[i]]

其中||是逻辑或运算。

优化:

1、若sum(array)为奇数,直接返回false
2、使用逆序循环将dp数组简化为一维数组


[l,r]区间很大,可以使用map保存已经计算过神奇数的数,之后如果有元素一致的数,可以直接查询结果。

如计算到”12345”为非神奇数,则之后遍历到”21345”、”23145”、”23415”、”23451”、“31245”、、、、都是非神奇数


#include <iostream>
#include <math.h>
#include <vector>
#include <algorithm>
#include <numeric>
#include <map>

using namespace::std;
//#define debug_
int lef = 0, righ = 0;

bool IsMagical(vector<char>& vec)
{
    int len = vec.size();
    int sum = accumulate(vec.begin(), vec.end(), 0);
    if (sum & 1)
        return false;

    int mid = (sum>>1);
    vector<int> dp(mid + 1, 0);
    dp[0] = 1;
    for (int i = 0; i < len; ++i) 
    {
        for (int j = mid; j > 0; --j)
        {
            if (j >= vec[i])
                dp[j] = max(dp[j], dp[j - vec[i]]);
        }
    }
    if (dp[mid])
        return true;
    else
        return false;
}

vector<char> getsortnum(int i)
{
    vector<char> vec;
    vec.reserve(10);
    int tmp;
    while (i)
    {
        tmp = i % 10;
        i = i / 10;
        vec.push_back(tmp);
    }
    sort(vec.begin(), vec.end());
    return vec;
}
void func(int lef, int righ)
{
    int count(0);
    bool flag;
    map<vector<char>, bool> my_map;

    for (auto i = lef; i <= righ; ++i)
    {
        vector<char> sorted_num;
        sorted_num.reserve(10);
        char tmp(0);
        int i_tmp(i);
        while (i_tmp)
        {
            tmp = i_tmp % 10;
            i_tmp = i_tmp / 10;
            sorted_num.push_back(tmp);
        }
        sort(sorted_num.begin(), sorted_num.end());

        auto iter = my_map.find(sorted_num);
        if (iter == my_map.end())
        {
            flag = IsMagical(sorted_num);
            my_map[sorted_num] = flag;
            if (flag)
                ++count;
        }
        else
        {
            if (iter->second)
                ++count;
        }
    }
    cout<< count<<endl;
}

int main()
{
#ifdef debug_
    lef = 1;
    righ = 50;
#else
    cin >> lef;
    cin >> righ;
#endif
    func(lef, righ);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值