C++/Qt 计算24点
游戏的算法可描述如下:4个1-10的数字,用加、减、乘、除和括号把数子算成24,每个数字都必须使用到,且只能用一次。
用C++写会更加的方便:
在这本书中要求了表达式中数字的顺序不能改变,所以在7.7节 中提供的算法不具有普遍适应性,但是算法的思路还是很简单并且清晰。不需要多动脑袋。在他的基础上,可以轻易的扩展成一般的算法。
一些比较难的24点计算
-
1 3 9 10
-
1 4 5 6
-
1 5 5 5
-
2 7 10 10
-
3 3 7 7
-
3 3 8 8
1、用递归分治算法思路及设计
【1】最开始是4个数,A、B、C、D。
【2】从4个数中选择两个数,例如 A 和 B 。
【3】将两个数进行运算,R1 = A OP B
【4】运算结果 R1 和 剩余的数字进行运算,R1、C、D
【5】从三个数中选择任意两个数进行运算
【6】继续运算,只至一个数字
【7】用递归方法,计算结果是否为24 ,很容易,但是要输出一条完整的表达式,很复杂,因为其简单的计算思路,值得笔记下来。表达式应该还有需要深思的地方…
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include <string>
#include <map>
using namespace std;
string ops[] = { "#","+","-","*","/","-","/" };
map <string, vector<string> > maps;
static int counts = 3;
string num_string( double n )
{
char buf[10];
sprintf( buf, "%g", n );
return string( buf );
}
double cal( double x, double y, int op )
{
switch( op )
{
case 1:return x + y;
case 2:return x - y;
case 3:return x * y;
case 4:
{
if( y == 0 )
return -1000;
return x / y;
}
default:
return -1000;
}
}
void findKeys( map <string, vector<string> > &m, string &v )
{
map <string, vector<string> >::iterator it;
it = m.find( v );
if( it != m.end() && counts > 0 )
{
counts--;
cout << "(";
for( int i = 0; i < 3; i++ )
{
findKeys( m, it->second[i] );
}
cout << ")";
}
else
{
cout << v;
}
}
bool is24( vector<double> a )
{
bool find = false;
if( a.size() == 1 )
return fabs( a[0] - 24 ) < 10E-5;
for( int i = 0; i < a.size(); i++ )
{
vector<double> b( a );
b.erase( b.begin() + i );
for( int j = 0; j < b.size(); j++ )
{
vector<double> c( b );
c.erase( c.begin() + j );
for( int op = 1; op <= 4; op++ )
{
vector<double> d( c );
double r = cal( a[i], b[j], op );
if( r < 0 )
continue;
else
d.push_back( r );
if( is24( d ) )
{
find = true;
vector<string> res;
res.push_back( num_string( a[i] ) );
res.push_back( ops[op] );
res.push_back( num_string( b[j] ) );
maps[num_string( r )] = res;
return true;
}
}
}
}
return false;
}
int main()
{
vector<double> a( 4, 0 );
while( cin >> a[0] >> a[1] >> a[2] >> a[3] )
{
maps.clear();
counts = 3;
if( is24( a ) )
{
cout << "true" << endl;
string s( "24" );
findKeys( maps, s);
cout << " = 24" << endl;
}
else cout << "false" << endl;
}
}
2、暴力穷举法
【1】四个数, 穷举 A、B、C、D
【2】三个符号,穷举 +、-、×、÷
【3】两种模式
【3.1】组成表达式,((A OP1 B) OP2 C ) OP3 D
【3.2】组成表达式,(A OP1 B) OP3 (C OP2 D)
【4】注意:减法和除法两个数字交换顺序后,会有不同结果,所以四则运算要分成6种。
对于减法,要检查是否为负数;对于除法,还要检查除数是否为0。
此时每一个数字和符号都已确定,可直接组合成完整的表达式。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include <string>
#include <map>
using namespace std;
string ops[] = { "#","+","-","*","/","-","/" };
string num_string( double n )
{
char buf[10];
sprintf( buf, "%g", n );
return string( buf );
}
double cal( double x, double y, int op )
{
switch( op )
{
case 1:return x + y;
case 2:return x - y;
case 3:return x * y;
case 4:
{
if( y == 0 )
return -1000;
return x / y;
}
case 5:
return y - x;
case 6:
{
if( x == 0 )
return -1000;
return y / x;
}
default:
return -1000;
}
}
bool findString( vector<string> &vec, const string &str )
{
for( const string var : vec )
{
if( var == str )
return true;
}
return false;
}
bool is24( vector<double> a )
{
vector < string > results;
bool find = false;
string res; //可以考虑使用逆波兰表达式,脱去括号,求得最终的表达式,加入表达式集,去除相同的部分
for( int A = 0; A < 4; A++ )
{
for( int B = 0; B < 4; B++ )
{
if( B == A ) continue;
for( int C = 0; C < 4; C++ )
{
if( C == A || C == B ) continue;
for( int D = 0; D < 4; D++ )
{
if( D == A || D == B || D == C ) continue;
for( int op1 = 1; op1 <= 4; op1++ )
for( int op2 = 1; op2 <= 6; op2++ )
for( int op3 = 1; op3 <= 6; op3++ )
{
double r1 = cal( a[A], a[B], op1 ); // (A op1 B) || (B op1 A)
if( r1 < 0 )
continue;
double r21 = cal( r1, a[C], op2 ); // (r1 op2 C) || (C op2 r1)
double r31 = cal( r21, a[D], op3 ); // (r21 op2 D) || (D op2 r21)
if( fabs( r31 - 24 ) < 10E-5 && ( r21 >= 0 ) )
{
//cout << "r31\n";
find = true;
if( op1 < 5 )
res = "(" + num_string( a[A] ) + ops[op1] + num_string( a[B] ) + ")";
else
res = "(" + num_string( a[B] ) + ops[op1] + num_string( a[A] ) + ")";
if( op2 < 5 )
res = "(" + res + ops[op2] + num_string( a[C] ) + ")";
else
res = "(" + num_string( a[C] ) + ops[op2] + res + ")";
if( op3 < 5 )
res = res + ops[op3] + num_string( a[D] );
else
res = num_string ( a[D] ) + ops[op3] + res;
//检查是否有同样的表达式
if( !findString( results, res ) )
results.push_back( res );
else
continue;
cout << res << "= 24" << endl;
}
double r22 = cal( a[C], a[D], op2 ); // (C op2 D) || (D op2 C)
double r32 = cal( r1, r22, op3 ); // (r1 op2 r22) || (r22 op2 r1)
if( fabs( r32 - 24 ) < 10E-5 && ( r22 >= 0 ) )
{
find = true;
string temp;
if( op1 < 5 )
res = "(" + num_string( a[A] ) + ops[op1] + num_string( a[B] ) + ")";
else
res = "(" + num_string( a[B] ) + ops[op1] + num_string( a[A] ) + ")";
if( op2 < 5 )
temp = "(" + num_string( a[C] ) + ops[op2] + num_string( a[D] ) + ")";
else
temp = "(" + num_string( a[D] ) + ops[op2] + num_string( a[C] ) + ")";
if( op3 < 5 )
res = res + ops[op3] + temp;
else
res = temp + ops[op3] + res;
//检查是否有同样的表达式
if( !findString( results, res ) )
results.push_back( res );
else
continue;
cout << res << "= 24" << endl;
}
}
}
}
}
}
if( !find )
{
cout << "Sorry ,无法计算\n";
return false;
}
else
return true;
}
int main()
{
vector<double> a( 4, 0 );
while( cin >> a[0] >> a[1] >> a[2] >> a[3] )
{
is24( a );
}
}
3、Qt 图片
#include "Widget.h"
#include <QtWidgets>
QString ops[] = { "#","+","-","*","/","-","/" };
int num[] = { 0,1,7,5,10 };
int idx = 0;
Widget::Widget(QWidget *parent) : QWidget(parent)
{
QPalette palette;
palette.setColor(QPalette::Window,Qt::red);
QHBoxLayout *labsLayout = new QHBoxLayout;
for (int i = 0; i < 4; ++i) {
labs[i] = new QLabel;
labs[i]->setAutoFillBackground(true);
labs[i]->setPalette(palette);
labs[i]->setFrameStyle(QFrame::Panel );
labs[i]->setAlignment(Qt::AlignCenter);
labs[i]->setMinimumHeight(50);
labs[i]->setMargin(10);
labsLayout->addWidget(labs[i]);
}
QGridLayout *btnsLayout = new QGridLayout;
for (int i = 0; i < 10; ++i) {
QPushButton *btn = new QPushButton(QString::number(i+1));
connect(btn,&QPushButton::clicked,[=](){
labs[idx]->setText(btn->text());
idx +=1;
if(idx==1){
for (int i = 1; i < 4; ++i) {
labs[i]->setText("");
}
edit->clear();
}
if(idx==4){
idx %= 4;
get24();
}
});
btnsLayout->addWidget(btn,i/5,i%5);
}
edit = new QTextEdit;
edit->setReadOnly(true);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addLayout(labsLayout);
mainLayout->addWidget(edit);
mainLayout->addLayout(btnsLayout);
}
double Widget::cal(double x, double y, int op)
{
switch( op )
{
case 1:return x + y;
case 2:return x - y;
case 3:return x * y;
case 4:
{
if( y == 0 )
return -1000;
return x / y;
}
case 5:
return y - x;
case 6:
{
if( x == 0 )
return -1000;
return y / x;
}
default:
return -1000;
}
}
bool Widget::findString(QVector<QString> &vec, const QString &str)
{
for( const QString var : vec )
{
if( var == str )
return true;
}
return false;
}
void Widget::get24()
{
num[1] = labs[0]->text().toInt();
num[2] = labs[1]->text().toInt();
num[3] = labs[2]->text().toInt();
num[4] = labs[3]->text().toInt();
QVector < QString > results;
bool find = false;
QString res; //可以考虑使用逆波兰表达式,脱去括号,求得最终的表达式,加入表达式集,去除相同的部分
for( int A = 1; A <= 4; A++ )
{
for( int B = 1; B <= 4; B++ )
{
if( B == A ) continue;
for( int C = 1; C <= 4; C++ )
{
if( C == A || C == B ) continue;
for( int D = 1; D <= 4; D++ )
{
if( D == A || D == B || D == C ) continue;
for( int op1 = 1; op1 <= 4; op1++ )
for( int op2 = 1; op2 <= 6; op2++ )
for( int op3 = 1; op3 <= 6; op3++ )
{
double r1 = cal( num[A], num[B], op1 ); // (A op1 B) || (B op1 A)
if( r1 < 0 )
continue;
double r21 = cal( r1, num[C], op2 ); // (r1 op2 C) || (C op2 r1)
double r31 = cal( r21, num[D], op3 ); // (r21 op2 D) || (D op2 r21)
// if( r31 == 24 && ( r21 >= 0 ) )
if( qAbs(r31 - 24)<10E-5 && ( r21 >= 0 ) )
{
//cout << "r31\n";
find = true;
if( op1 < 5 )
res = "(" + QString::number( num[A] ) + ops[op1] + QString::number( num[B] ) + ")";
else
res = "(" + QString::number( num[B] ) + ops[op1] + QString::number( num[A] ) + ")";
if( op2 < 5 )
res = "(" + res + ops[op2] + QString::number( num[C] ) + ")";
else
res = "(" + QString::number( num[C] ) + ops[op2] + res + ")";
if( op3 < 5 )
res = res + ops[op3] + QString::number( num[D] );
else
res = QString::number( num[D] ) + ops[op3] + res;
//检查是否有同样的表达式
if( !findString( results, res ) )
results.push_back( res );
else
continue;
// qDebug() << res << "= 24" ;
edit->append(res+" = 24");
}
double r22 = cal( num[C], num[D], op2 ); // (C op2 D) || (D op2 C)
double r32 = cal( r1, r22, op3 ); // (r1 op2 r22) || (r22 op2 r1)
if( qAbs(r32 - 24)<10E-5 && ( r22 >= 0 ) )
{
find = true;
QString temp;
if( op1 < 5 )
res = "(" + QString::number( num[A] ) + ops[op1] + QString::number( num[B] ) + ")";
else
res = "(" + QString::number( num[B] ) + ops[op1] + QString::number( num[A] ) + ")";
if( op2 < 5 )
temp = "(" + QString::number( num[C] ) + ops[op2] + QString::number( num[D] ) + ")";
else
temp = "(" + QString::number( num[D] ) + ops[op2] + QString::number( num[C] ) + ")";
if( op3 < 5 )
res = res + ops[op3] + temp;
else
res = temp + ops[op3] + res;
//检查是否有同样的表达式
if( !findString( results, res ) )
results.push_back( res );
else
continue;
// qDebug() << res << "= 24";
edit->append(res+" = 24");
}
}
}
}
}
}
if( !find )
edit->append("Sorry ,无法计算") ;
else
edit->moveCursor(QTextCursor::Start);
}
有感兴趣的 可以直接下载 0 积分
https://download.csdn.net/download/hitzsf/85750810, 0积分下载