ACM:搜索算法专题(1)——24点

来源:互联网 发布:2017七天网络成绩查询 编辑:程序博客网 时间:2024/05/01 08:02
题目描述:
    给定4个数字,判定这4个数字是否可以通过运算得到结果24。运算操作包括:加、减、乘、除,允许变换数字的顺序,允许使用括号改变运算顺序。
    即:判定是否存在一种通过在下面的圆圈中添加运算符以及添加括号的方式使得等式成立:
           
a ○ b ○ c ○ d = 24
    例:数字 5, 5, 5, 1 可以通过运算得到结果24: 
            5 × (5 - 1 ÷ 5) = 24
        数字 9, 9, 9, 9 则无论通过怎样的运算都无法得到24的结果。

解答:
    本题还是比较简单的,由于数据量比较少,因此可以采用暴力搜索的方式进行解答,枚举所有的可能的运算方式,如果有1种方案可以达到24,则表明给定的数据有解,否则无解。
    枚举的方式如下:
    由于加法和乘法满足交换律,而减法和出发则不满足,这里我们添加两种运算:“反减”和“反除”,分别记作 ~- 和 ~÷,此时:
                        a ~-  b = b -  a
                        a ~÷ b = b ÷ a
    添加这两种运算操作后,就使得减法和除法也同样符合交换律。此时,所有情况的运算顺序就只有两种情况,用※表示任意的运算符,则两种运算顺序为:
        ((a 
※ b) ※ c) ※ d))         <从左到右依次计算>
        ((a 
※ b) ※ (c ※ d))        <分别计算前两个和后两个数字的结果后,在将得到的两个结果进行运算,得到最终的结果>

    而其他的运算顺序均可以通过调整数字的排列顺序得到用以上两种情况表示的等价情况,例如:
        (a 
※ ((b ※ c) ※ d))    =====>  (((b ※ c) ※ d) ※ a) 
       
 ((a ※ (b ※ c)) ※ d)    =====>  (((b ※ c) ※ a) ※ d)
    这样,通过枚举4个数字排列情况和三个位置的运算符的不同情况,就可以枚举到所有的运算情况。其中:4个数字排列,共有4!= 24种结果,而3个运算符中每个运算符都有6种不同的情况,因此共有6^3 = 216中情况,而运算顺序又有2中情况,因此,总的情况数为:
                            24 × 216 × 2 = 10368
    由于加法和乘法本身就具有交换律,并且给定的4个数字也有某些数字相同的情况,因此,在实际枚举过程中,10368种情况会有某些是重复的。本题数据量比较小,因此重复计算的问题可以忽略。

输入输出格式:
    输入:第1行:1个正整数, t,表示数据组数;第2..t+1行:4个正整数, a,b,c,d
    输出:对每组测试数据输出一行,表明能
否计算出24点。若能够输出"Yes",否则输出"No"。

数据范围:
     2 ≤ t ≤ 100
     
1 ≤ a,b,c,d ≤10 

程序代码:

/****************************************************//* File        : Hiho_Week_98                       *//* Author      : Zhang Yufei                        *//* Date        : 2016-05-16                         *//* Description : HihoCoder ACM program. (submit:g++)*//****************************************************/#include<stdio.h>#define DATA_TYPE float#define INPUT_PATTERN "%f"// Record the input data.DATA_TYPE data[4];/* Record the operator: *0: Add1: Substract *  2: Multiply 3: Devide *  4: Reserve_Substract *5: Reserve_Devide. */int op_value;// Record if the current calculate is legal.int tag;/* * This function computes the result according to given * data and operator. * Parameters: *@a & @b: The data to compute. *@op: The operator. * Returns: *The result according to given data and operator, *if the equation is illegal, returns -1. */DATA_TYPE compute(DATA_TYPE a, DATA_TYPE b, int op) {switch(op) {case 0: return a + b; break;case 1: return a - b; break;case 2: return a * b; break;case 3: if(b == 0) {tag = 0;return -1;} else {return a / b;}break;case 4: return b - a;case 5: if(a == 0) {tag = 0;return -1;} else {return b / a;}break;}}/* * This function checks if the data can get result 24. * Parameters: *@index: The current index. * Returns: *If the data can get result 24, returns 1, *or returns 0. */int check(int index) {if(index == 4) {for(op_value = 0; op_value < 216; op_value++) {int op1 = op_value % 6;int op2 = op_value / 6 % 6;int op3 = op_value / 36;tag = 1;if(compute(compute(compute(data[0], data[1], op1), data[2], op2), data[3], op3) == 24 && tag) { return 1;}tag = 1;if(compute(compute(data[0], data[1], op1), compute(data[2], data[3], op3), op2) == 24 && tag) {return 1;}}return 0;}for(int i = index; i < 4; i++) {DATA_TYPE swap = data[index];data[index] = data[i];data[i] = swap;if(check(index + 1)) {return 1;}swap = data[index];data[index] = data[i];data[i] = swap;}return 0;}/* * This function deals with one test case. * Parameters: *None. * Returns: *None. */void function(void) {for(int i = 0; i < 4; i++) {scanf(INPUT_PATTERN, &data[i]);}if(check(0)) {printf("Yes\n");} else {printf("No\n");}}/* * The main program. */int main(void) {int t;scanf("%d", &t);for(int i = 0; i < t; i++) {function();}return 0;}


0 0
原创粉丝点击