在浏览圈子讨论区的时候,发现有人在讨论机械求解24点的问题。其实求24点的程序写起来一点都不难,我记得以前大一的时候就写过一个,无奈找了半天都找不到,可能是重装系统的时候丢失了。好在今天休息,于是就静下心来写了一个。为了便于大家移植,我是用纯C写的。
本程序的输入是一个名叫Inpute.txt的文本文件,里面存放着4个数和计算目标(这个程序可以指定计算结果,不是24也可以)。输出是一个名叫Result.txt的文本文件,由程序计算产生,记录的是运算步骤。
Inpute.txt样例:
[3][3][8][8]=[24]
Result.txt样例:
0000:
第一步:{8.000000 / 3.000000 = 2.666667}
第二步:{3.000000 - 2.666667 = 0.333333}
第三步:{8.000000 / 0.333333 = 24.000000}
共有1种解。
程序源代码(C文件):
- #include <stdio.h>
- #include <conio.h>
- #include <string.h>
- #define OPER_NUM 4
- char s_cvOperator[OPER_NUM] = {'+', '-', '*', '/'};
- char s_cvOperType[OPER_NUM] = { 0, 1, 0, 1};
- double s_dTarget;
- double s_dvVals[4];
- char s_cvOpers[3];
- char s_cvUsed[4];
- int s_iIndex;
- int s_iNum;
- double s_dvRecords[3][2];
- char s_sivSave[OPER_NUM * OPER_NUM * OPER_NUM * 24][200];
- double Compute(double v1, double v2, char oper);
- char Scan();
- char Outport();
- void main()
- {
- int r;
- FILE * fp, * ofp;
- s_dvVals[0] = 3;
- s_dvVals[1] = 3;
- s_dvVals[2] = 8;
- s_dvVals[3] = 8;
- ofp = fopen("Result.txt", "w");
- if(ofp)
- {
- /* 清空输出文件 */
- fclose(ofp);
- /* 读取输入文件 */
- fp = fopen("Input.txt", "r");
- if(fp)
- {
- r = fscanf(fp,
- "[%lf][%lf][%lf][%lf]=[%lf]",
- &s_dvVals[0],
- &s_dvVals[1],
- &s_dvVals[2],
- &s_dvVals[3],
- &s_dTarget);
- fclose(fp);
- if(r == 5)
- {
- /* 搜索解 */
- s_iIndex = 0;
- s_iNum = 0;
- Scan();
- ofp = fopen("Result.txt", "a");
- if(ofp)
- {
- fprintf(ofp, "共有%d种解。/n", s_iNum);
- fclose(ofp);
- }
- return;
- }
- }
- ofp = fopen("Result.txt", "a");
- if(ofp)
- {
- fprintf(ofp, "读取输入文件时出错!/n注意文件格式,如:[3][3][8][8]=[24]/n", s_iNum);
- fclose(ofp);
- }
- }
- else
- {
- printf("打开输出文件失败!/n");
- getch();
- }
- }
- double Compute(double v1, double v2, char oper)
- {
- switch(oper)
- {
- case '+':
- return v1 + v2;
- break;
- case '-':
- return v1 - v2;
- break;
- case '*':
- return v1 * v2;
- break;
- case '/':
- return v1 / v2;
- break;
- default:
- return 0.0;
- break;
- }
- return 0.0;
- }
- char Scan()
- {
- int i, j, k;
- double tmp;
- double t;
- s_iIndex++;
- /* 取得一个操作数 */
- for(i = 0; i < 4; i++)
- {
- if(s_cvUsed[i] != 1)
- {
- s_cvUsed[i] = 1;
- /* 取得第二个操作数 */
- for(j = 0; j < 4; j++)
- {
- if(s_cvUsed[j] != 1)
- {
- /* 记录这个操作数 */
- tmp = s_dvVals[j];
- /* 遍历所有支持的运算符 */
- for(k = 0; k < OPER_NUM; k++)
- {
- s_cvOpers[s_iIndex - 1] = s_cvOperator[k];
- s_dvRecords[s_iIndex - 1][0] = s_dvVals[i];
- s_dvRecords[s_iIndex - 1][1] = tmp;
- /* 避免重复 */
- if( s_cvOperType[k] == 0
- && s_dvRecords[s_iIndex - 1][0] > s_dvRecords[s_iIndex - 1][1])
- {
- t = s_dvRecords[s_iIndex - 1][0];
- s_dvRecords[s_iIndex - 1][0] = s_dvRecords[s_iIndex - 1][1];
- s_dvRecords[s_iIndex - 1][1] = t;
- }
- s_dvVals[j] = Compute(
- s_dvRecords[s_iIndex - 1][0],
- s_dvRecords[s_iIndex - 1][1],
- s_cvOperator[k]);
- if(s_iIndex == 3)
- {
- if(s_dvVals[j] > s_dTarget - 0.00001 && s_dvVals[j] < s_dTarget + 0.00001)
- {
- if(Outport())
- {
- s_iNum++;
- }
- }
- }
- else
- {
- Scan();
- }
- }
- /* 恢复这个操作数 */
- s_dvVals[j] = tmp;
- }
- }
- s_cvUsed[i] = 0;
- }
- }
- s_iIndex--;
- return 0;
- }
- char Outport()
- {
- FILE * fp;
- int i;
- char cRepeated = 0;
- char siTmp[200];
- sprintf(siTmp,
- " 第一步:{%lf %c %lf = %lf}/n"
- " 第二步:{%lf %c %lf = %lf}/n"
- " 第三步:{%lf %c %lf = %lf}",
- s_dvRecords[0][0],
- s_cvOpers[0],
- s_dvRecords[0][1],
- Compute(
- s_dvRecords[0][0],
- s_dvRecords[0][1],
- s_cvOpers[0]),
- s_dvRecords[1][0],
- s_cvOpers[1],
- s_dvRecords[1][1],
- Compute(
- s_dvRecords[1][0],
- s_dvRecords[1][1],
- s_cvOpers[1]),
- s_dvRecords[2][0],
- s_cvOpers[2],
- s_dvRecords[2][1],
- Compute(
- s_dvRecords[2][0],
- s_dvRecords[2][1],
- s_cvOpers[2]));
- /* 重复检查 */
- for(i = 0; i < s_iNum; i++)
- {
- if(strcmp(siTmp, s_sivSave[i]) == 0)
- {
- cRepeated = 1;
- break;
- }
- }
- if(cRepeated == 0)
- {
- strcpy(s_sivSave[s_iNum], siTmp);
- fp = fopen("Result.txt", "a");
- if(fp)
- {
- fprintf(fp, "%04d:/n%s/n", s_iNum, siTmp);
- fclose(fp);
- }
- }
- return 1 - cRepeated;
- }