題目鏈接:
http://hihocoder.com/problemset/problem/1304
24點規則,抽取撲克中的四張牌,每張牌使用一次的情況下進行三次加減乘除運算,考慮是否能得到24這個數。
首先是解題思路,在題目裏也有給出,這裏我自己做了歸納;
1.定義運算符 ⊙:
用於表示6種運算,在原本的加、減、乘、除的基礎上加上被減、和被除;
被減的意思是交換兩個數在減和除運算符的前後位置,比如a-b還可以有b-a這種情況。
2.兩種模式:
(((a⊙b)⊙c)⊙d) 和
((a⊙b)⊙(c⊙d));
3.複雜度計算:
4個數字全排列表示所有數字位置情況:4!=24
3個運算符⊙,每個有6種情況:6^3 = 216
兩種模式 : x2
所以:24 * 216 * 2= 10368
又因爲 a+b與a*b分別等價於b+a與b * a;
所以總情況肯定小於10368.
下面是代碼實現思路:
1.先搜索全排列,再搜索運算符。
2.搜索數字時注意標記每個數字使用一次,而每個運算可以使用多次。
3.兩種模式的計算方法(具體見代碼)
我自己照着上述思路寫了100多一點行,而在網上看到有大牛簡化寫只用了50左右,佩服,也貼在下方。
這是我自己寫的:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int num[4];
int used[4] = { 0 };
int nowNumber[4] = { 0 };
char ops[6] = { '+','-','*','/','$','&' };
char nowOps[3];
int ant = 0;
bool makeOps(int depth2);
double calc(double sum, char c, double d)
{
if (c == '+')
return sum + d;
if (c == '-')
return sum - d;
if (c == '*')
return sum*d;
if (c == '/')
return sum / d;
if (c == '$')
return d - sum;
if (c == '&')
return d / sum;
}
double calcType1(int nowNumber[], char nowOps[])
{
double sum = nowNumber[0];
for (int l1 = 0; l1<3; l1++)
{
sum = calc(sum, nowOps[l1], nowNumber[l1 + 1]);
}
return sum;
}
double calcType2(int nowNumber[], char nowOps[])
{
double sum1 = nowNumber[0];
double sum2 = nowNumber[2];
double sum;
sum1 = calc(sum1, nowOps[0], nowNumber[1]);
sum2 = calc(sum2, nowOps[2], nowNumber[3]);
sum = calc(sum1, nowOps[1], sum2);
return sum;
}
bool makeNumber(int depth1)
{
if (depth1 >= 4)
{
if (makeOps(0))
return true;
else return false;
}
for (int i = 0; i<4; i++)
{
if (used[i] == 0)
{
nowNumber[depth1] = num[i];
used[i] = 1;
if (makeNumber(depth1 + 1))
{
return true;
}
used[i] = 0;
}
}
return false;
}
bool makeOps(int depth2)
{
if (depth2 >= 3)
{
if (calcType1(nowNumber, nowOps) == 24)
{
//cout<<"("<<"("<<"("<<nowNumber[0]<<nowOps[0]<<nowNumber[1]<<")"<<nowOps[1]<<nowNumber[2]<<")"<<nowOps[2]<<nowNumber[3]<<")"<<endl;
return true;
}
else if (calcType2(nowNumber, nowOps) == 24)
{
//cout<<"("<<"("<<nowNumber[0]<<nowOps[0]<<nowNumber[1]<<")"<<nowOps[1]<<"("<<nowNumber[2]<<nowOps[2]<<nowNumber[3]<<")"<<")"<<endl;
return true;
}
return false;
}
for (int j = 0; j<6; j++)
{
nowOps[depth2] = ops[j];
if (makeOps(depth2 + 1))
{
return true;
}
}
return false;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
memset(used, 0, sizeof(used));
memset(nowNumber, 0, sizeof(nowNumber));
memset(nowOps, 0, sizeof(nowOps));
for (int w = 0; w<4; w++)
{
scanf("%d", &num[w]);
}
if(makeNumber(0))
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
return 0;
}
這是大牛的簡化:http://blog.csdn.net/qq_28954601/article/details/51425433
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
double a[4];
bool flag;
double so(double a,double b,int k)
{
double s=0.0;
switch(k)
{
case 0:s=a+b;break;
case 1:s=a-b;break;
case 2:s=a*b;break;
case 3:if(b!=0)s=a/b;break;
case 4:s=b-a;break;
case 5:if(a!=0)s=b/a;break;
}
return s;
}
bool pan(int i,int j,int k)
{
if(so(so(so(a[0],a[1],i),a[2],j),a[3],k)==24)return true;
if(so(so(a[0],a[1],i),so(a[2],a[3],k),j)==24)return true;
return false;
}
void solve()
{
for(int i=0; i<6; i++)
for(int j=0; j<6; j++)
for(int k=0; k<6; k++)
if(pan(i,j,k))
{
flag=true;
return;
}
}
int main()
{
int N;
cin>>N;
while(N--)
{
flag=false;
for(int i=0; i<4; i++)
cin>>a[i];
sort(a,a+4);
do
{
solve();
if(flag)break;
}
while(next_permutation(a,a+4));
if(flag)printf("Yes\n");
else printf("No\n");
}
return 0;
}