华为机试HJ67:24点游戏算法

Posted 翟天保Steven

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了华为机试HJ67:24点游戏算法相关的知识,希望对你有一定的参考价值。

作者:Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

题目描述:

问题描述:给出4个1-10的数字,通过加减乘除,得到数字为24就算胜利
输入:
4个1-10的数字。[数字允许重复,但每个数字仅允许使用一次,测试用例保证无异常数字。
输出:

true or false

本题含有多组样例输入。

输入描述:

输入4个int整数

输出描述:

返回能否得到24点,能输出true,不能输出false

示例:

输入:

7 2 1 10

输出:

true

解题思路:

本题是深度优先遍历dfs的经典题目:输入4个1-10的数字,用加减乘除使其结果为24。用dfs函数进行递归遍历求解,当计算到第四步时,step为3,此时判断是否为24,若有结果则令flag为true;声明num数组存放数字,声明visit数组存放当前数字是否可用。

假设输入数字为7654,则第一个遍历为7+6+5+4,再7+6+5-4。。。再7+6-5+4。。。。再7+6+4+5。。。以此类推。另外,dfs扔进去的和是前面的所有值计算完的结果再操作后面的值,换句话说,7+6+5*4,它扔进去的是(7+6+5)*4,虽然此时计算的结果和预想的不一样,别忘了还有排序,后面会有5*4+7+6的计算表达式,这样就确保了该计算的表达式依然会进行计算。

注意:因为sum初始为0,所以要考虑一下不同情况,不然会出现0*X=0。

测试代码:

#include <iostream>

using namespace std;

double num[4];
bool flag=false;
bool visit[4]={0};

void dfs(int step,double sum)
{
    if(flag)
        return;
    if(step==3)
    {
        if(sum==24.)
        {
            flag=true;
            return;
        }
    }
    else{
        step++;
        for(int i=0;i<4;++i)
        {
            if(!visit[i])
            {
                visit[i]=true;
                dfs(step,sum+num[i]);
                dfs(step,sum-num[i]);
                if(step!=0){
                    dfs(step,sum*num[i]);
                    dfs(step,sum/num[i]);
                }
                visit[i]=false;
                if(flag)
                    return;
            }
        }
    }
    
}

int main()
{
    while(cin>>num[0]>>num[1]>>num[2]>>num[3])
    {
        dfs(-1,0);
        if(flag)
        {
            cout<<"true"<<endl;
        }
        else{
            cout<<"false"<<endl;
        }

        flag=false;
        num[4]={0};
        visit[4]={0};
    }
    return 0;
}

       后来测试我发现,1 9 1 2这个例子过不了,但是(9-1)*(2+1)=24,这是因为上面的算法考虑括号操作不周全导致的,牛客一名大佬“ultraji” 所提供的的算法思路更完善些,在此分享给大家。

       其逻辑是:借用next_permutation函数排布4个数字的顺序,往里面塞入3个运算符,再用for循环处理各种可能的括号情况。其代码如下:

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

double op(double a, double b, int opera)
{
    if(opera == 0) return a+b;
    else if(opera == 1) return a-b;
    else if(opera == 2) return a*b;
    else if(opera == 3) return a/b;
    return 0;
}

bool cal24(vector<double> a, vector<int> o)
{
    // 考虑括号导致优先级变化
    bool flag = false;
    if(o.empty()) {
        if( fabs(a[0]-24.0) < 0.01) flag = true;
    } else {
        for (int i = 0; i < o.size() && !flag; i++)
        {
            a[i] = op(a[i], a[i+1], o[i]);
            a.erase(a.begin()+i+1);
            o.erase(o.begin()+i);
            flag |= cal24(a, o);
        }
    }
    return flag;
}

int main()
{
    double a[4];
    int o[3];
    while(cin >> a[0] >> a[1] >> a[2] >> a[3])
    {
        bool flag = false;
        sort(a, a+4);
        do {
            for(int i = 0; i < 4 && !flag; i++) {
                o[0] = i;
                for(int j = 0; j < 4 && !flag; j++) {
                    o[1] = j; 
                    for(int k = 0; k < 4 && !flag; k++) {
                        o[2] = k;
                        vector<double> va(a, a+4);
                        vector<int> vo(o, o+3);
                        if(cal24(va, vo)) flag = true;
                    }
                }
            }
        } while (next_permutation(a, a+4) && !flag);
        if( flag ) cout << "true" << endl;
        else cout << "false" << endl;
    }
    return 0;
}

以上是关于华为机试HJ67:24点游戏算法的主要内容,如果未能解决你的问题,请参考以下文章

华为机试HJ89:24点运算

华为机试HJ21:简单密码

华为机试HJ24:合唱队

华为机试HJ40:统计字符

华为机试HJ88:扑克牌大小

华为机试HJ88:扑克牌大小