24点问题C实现(2011年12月23日22:55:00)

问题描述

 

/*
Description

求24点问题。给定4个正整数,用算术运算符+,-,*,/将这4个正整数连接起来,
使其最终结果恰为24。如果能得到24,输出Yes,否则输出No。


数据输入:

第一行是一个整数N(1<=N<=20),表示有多少个测试例子。以下每行为一个测试例子,每行有四个正整数。


数据输出:

每行输出对应测试例子的结果。

Sample Input

2
1 2 3 7
2 2 2 2


Sample Output

Yes
No
*/


分析:

 

/**
分析:4个数中任意两个用六种运算得到一个结果,将其赋给辅助数组的第一个位置,
其他两个没有选取的赋给第二个和第三个元素;递归调用,直到得到结果,判断结果是不是24
如果不是,当传递的操作数个数为两个时,则换一个操作符试试看能不能使其得到结果为24
六种都试过后,那就得回溯到三个操作数的时候了,回溯即把辅助数组的元素还原,当然每次调用之前都把辅助数组
拷贝一份给操作数就不需要将值再赋值回赋值数组了,
为什么要回溯或者是要用到拷贝主要是因为这个公用的数组在使用时会发生变化,
当要回溯时,直接将拷贝的数据复制给它就行了
回到三个操作数那一层时,再去试试其他操作符,然后再递归调用,或者都不行,回溯到四个操作数那一层。
直到所以的操作都试了 还是得不到24 再去换其他任意两个数 继续这样的操作 知道所以的组合全部试完
仍然得不到24的话 返回false 如果有一个得到24 直接返回true 毕竟这里不是要你求所以的组合
*/

 

//实现

 

//头文件申明部分

#include <stdio.h>
#include <stdlib.h>

int assists[3] = {0,0,0};
int calculate(int);
bool judge(int *,int);


//主函数部分

 

int main()
{
    int cases,input[4],i;

    scanf("%d",&cases);

    while(cases--)
    {
        for(i=0; i<4; i++)
        {
            scanf("%d",&input[i]);
        }

        if(judge(input,4))
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }
    }
    system("pause");
    return 0;
}


//六种可能的运算

int calculate(int num1,int num2,int operate)
{
    //乘法和加法有交换律
    //做除法时 除数为零和除不尽都返回30000 表示不用考虑这种情况
    switch(operate)
    {
    case 1:
        return num1 + num2;
        break;
    case 2:
        return num1 - num2;
        break;
    case 3:
        return num1 * num2;
        break;
    case 4:
        return num2 - num1;
        break;
    case 5:
        return ((num2 != 0 && num1 % num2 == 0)?(num1/num2):10000);
        break;
    case 6:
        return ((num1 != 0 && num2 % num1 == 0)?num2/num1:10000);
        break;
    }
}


//判断主体部分

 

bool judge(int *p,int count)
{
    bool result = false;
    int i,j,k,n,operators[6],input[4],a=0;

    //先将数组拷贝一份
    for(i=0; i<count; i++)
    {
        input[i] = p[i];
        //printf("%d\n",p[i]);
    }

    for(i=0; i<6; i++)
    {
        operators[i] = i + 1;
    }
    for(i=0; i<count; i++)
    {
        for(j=0; j<count&&j!=i; j++)
        {
            //printf("_______________________________________\n");
            for(k=0; k<6; k++)
            {

                if(calculate(input[i],input[j],operators[k]) != 10000)
                {
                    //完成第一次运算
                    assists[0] =  calculate(input[i],input[j],operators[k]);
                    //printf("%d--------------------\n",assists[0]);


                    if(count == 4)
                    {
                        bool flag = true;
                        //给其他两个操作数赋值
                        for(n=0; n<count; n++)
                        {
                            if(n != i && n != j && flag)
                            {
                                assists[1] = input[n];
                                //printf("%d===\n",assists[1]);
                                flag = false;
                                continue;
                            }
                            else if(n != i && n != j)
                            {
                                assists[2] = input[n];
                                //printf("%d===\n",assists[2]);
                            }
                            else
                            {
                                continue;
                            }

                        }

                        //调用自身,操作数个数减1
                        result = judge(assists,count-1);
                        if(!result)
                        {
                            if(k == 5)
                            {
                                break;  //不需要回溯,直接退出这个循环,再选取另外两个
                            }

                            continue;  //继续试试新的操作数
                        }
                        else
                        {
                            return true;
                        }

                    }
                    else if(count == 3)
                    {
                        for(n=0; n<count; n++)
                        {
                            if(n != i && n != j)
                            {
                                assists[1] = input[n];
                                //printf("%d===\n",assists[1]);
                                break;
                            }
                            else
                            {
                                continue;
                            }

                        }

                        if(!judge(assists,count-1))
                        {
                            if(k == 5)
                            {
                                //assists[0] = input[0];  //回溯,返回有4个操作数时再进行判断
                                return false;
                            }
                            continue;   //继续试试新的操作
                        }
                        else
                        {
                            //printf("HelloWolrd3\n");
                            return true;   //成功返回
                        }
                    }
                    else if(count == 2)
                    {
                        if(assists[0] == 24)
                        {
                            //printf("HelloWolrd2\n");
                            return true;
                        }

                        if(k == 5)
                        {
                            //assists[0] = input[0];   //回溯
                            //assists[1] = input[1];
                            return false;            //返回3个操作数的时刻
                        }
                        else
                        {
                            //printf("%d++++++++++++++++\n",a++);
                            continue;//试试其他操作符
                        }
                    }
                }

                else
                {
                    continue;
                }
            }

        }
    }

    return false;  //能到达这里 说明前面的都没有成功 最后返回false
}



提交结果:AC

 

过程有点复杂,本人菜鸟级,求大神给出优化解!!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值