C++笔试题 送木板

描述

木板商开业大酬宾,免费赠送木板。老板给每个客人准备了N块木板。客人必须按以下规则去拿木板:客人每次可以拿M块木板M是N的质因数M <= 根号N。这时, 木板商就会在客人拿走M块木板后再拿走M块木板。然后客人可以接着拿木板。有一个木匠他非常想知道最多可以拿到多少块木板,请你写个程序告诉他。

输入描述

一个整数N,N <= 100000

输出描述

能拿到木板数量的最大值

样例输入 1

16

样例输出 1

8

试题解析

拿到这道题后,我们需要知道木匠最多只能拿到一半的木板,因为木板商会在客人拿走M块木板后再拿走M块木板。当然,这个与N有关,也与木匠拿木板的策略有关系。

我采用了两种方法:
第一种方法:如果我们把N当作节点,M当作权值,那么N到N’ (=N-2*M)作为边,就可以得到一条有向图的边,全部方案有点像一棵树,你需要根据有向图,遍历所有的方案,找出权值最大的路径。

第二种方法:我们从2开始,逐次找到每个质因数M,然后顺序计算,一直到N<4,但这种方法有一个毛病,如果N’ = 6K (K>=2), 我们会顺序先选择M=2,导致最后的余数是2, 因此,当最后余数是2的时候,我们要重算一次,当N = 6K (K>=2)的时候,先选择M=3,这样,就会避免余数为2。

下面的代码是第二种方法的,经过不完全测试。老板给每个客人准备了N块木板, 木匠拿到的木板数有四种情况:

  1. 拿到0块,如果N是质数, 最后余数是N,例如:2, 7,11等
  2. 拿到一半的木板,最后余数是0,例如N=4, 8, 56等
  3. 拿到 (N-2)/2的木板,最后的余数是2,例如N=6, 10, 14
  4. 拿到 (N-3)/2的木板,最后的余数是3,例如N=9, 15等
#include 
#include 

using namespace std;

//#define UNIT_TEST
//#define UNIT_TEST_DETAILS

#ifdef UNIT_TEST_DETAILS
class OneStep
{
public:
    int N;
    int M;
    int r;  // remainder
};
#endif

class GiftWoodenBoards
{
private:
    bool checkPrimeDivisor(int n, int m);

public:
    int  GiftMaxWoodenBoardsPlus(int n, int reminder);
    bool checkPrime(int n);
};

bool GiftWoodenBoards::checkPrime(int n)
{
    if (n < 2 || n % 2 == 0 && n>3)
    {
        return false;
    }

    for (int i = 3; i <= (int)sqrt(double(n)); i += 2)
    {
        if (n%i == 0)
        {
            return false;
        }
    }
    return true;
}
    
bool GiftWoodenBoards::checkPrimeDivisor(int N, int M)
{
    if (N % M == 0 && true == checkPrime(M))
    {
        return true;
    }
    return false;
}

int GiftWoodenBoards::GiftMaxWoodenBoardsPlus(int N, int reminder)
{
#ifdef UNIT_TEST_DETAILS
    vector<OneStep> step_vec;
    OneStep one_step;
#endif
    int tmpN = N;
    int sumOfM = 0;
    int M = 2;

    while (N > 3 && M <= (int)sqrt((double)N))
    {
        if (N % 6 == 0 && N / 6 >= 2 && reminder > 0)
        {
            sumOfM += 3;
#ifdef UNIT_TEST_DETAILS
            one_step.M = 3;
            one_step.N = N;
            one_step.r = tmpN - 2 * sumOfM;
            step_vec.push_back(one_step);
#endif
            N -= 6;
            reminder = 0;
        }
        else if (true == checkPrimeDivisor(N, N / 2) &&
                 N / 2 <= (int)sqrt((double)N))
        {
            sumOfM += N / 2;
#ifdef UNIT_TEST_DETAILS
            one_step.M = N / 2;
            one_step.N = N;
            one_step.r = tmpN - 2 * sumOfM;
            step_vec.push_back(one_step);
#endif
            N = 0;
        }
        else if (true == checkPrimeDivisor(N, M))
        {
            sumOfM += M;
#ifdef UNIT_TEST_DETAILS
            one_step.M = M;
            one_step.N = N;
            one_step.r = tmpN - 2 * sumOfM;
            step_vec.push_back(one_step);
#endif
            N -= 2 * M;
            M  = 2;
        }
        else
        {
            M++;
            if (M % 2 == 0) // if M=4, 6, 8, 10, ...
            {
                M++; // M=5, 7, 9, 11, ...
            }
        }
    }

#ifdef UNIT_TEST_DETAILS
    for (auto x : step_vec)
    {
        cout << "(" << x.M << "," << x.N << "," << x.r << ")  ";
    }
    cout << endl;
#endif

    return sumOfM;
}

int main()
{
    int N;
    GiftWoodenBoards gift_wooden_boards;

#ifndef UNIT_TEST    
    cin >> N;
#else
    for (N = 2; N <= 200; N++)
#endif
    {
        int sumOfM = gift_wooden_boards.GiftMaxWoodenBoardsPlus(N, 0);
        if (false == gift_wooden_boards.checkPrime(N) && N > 2 * sumOfM)
        {
            if (2 == N - 2 * sumOfM)
            {
                int sumOfM_new = gift_wooden_boards.GiftMaxWoodenBoardsPlus(N, N - 2 * sumOfM);
#ifdef UNIT_TEST
                cout << "N = " << N << ", new sumOfM = " << sumOfM_new;
                cout << ", old reminder = " << N - 2 * sumOfM;
                cout << ", new reminder = " << N - 2 * sumOfM_new << endl;
#else
                cout << sumOfM_new << endl;
#endif
            }
            else
            {
#ifdef UNIT_TEST
                cout << "N = " << N << ", sumOfM = " << sumOfM;
                cout << ", reminder = " << N - 2 * sumOfM << endl;
#else
                cout << sumOfM << endl;
#endif
            }
        }
        else
        {
#ifdef UNIT_TEST
            cout << "N = " << N << ", sumOfM = " << sumOfM;
            cout << ", reminder = " << N - 2 * sumOfM << endl;
#else
            cout << sumOfM << endl;
#endif
        }
    }
    
    return 0;
}

你可能感兴趣的:(C++,招聘笔试题)