题目
题目链接
题意
给出4个数字,让你任意指定运算符(3个)、增加括号、交换数,问组成24点的代价最小是多少。
增加括号:代价为1。
交换数的顺序:代价为2。
题解
方法就是暴力枚举,我们可以先枚举数的顺序(4!4!种可能性),再枚举运算符类型(4343种可能性),再枚举表达式树的结构(55种情况,计算可以使用卡特兰数计算)。
然后在把枚举的数的顺序、运算符填入表达式树中去。
至于填括号的操作,我们在一颗完整的表达式树构造完成后,可以判断节点下是否有直接有+、−+、−,有几个+、−+、−就要增加几对括号。
这样的话费用就计算出来了,下面只需要按照后序遍历计算表达式树,判断结果是否为24就可以了。
注意如果不能整除的话,要提前终止计算,返回当前情况不满足。
在我写这道题的时候,排列、排列的代价、表达式树的结构种类我都手动计算出来了,所以在这道题里面,显得比较暴力。
代码
#include <iostream>
#include <algorithm>
using namespace std;
int a[4],na[4];
int ps[][4] = {{0,1,2,3},{0,1,3,2},{0,2,1,3},{0,2,3,1},{0,3,1,2},{0,3,2,1},{1,0,2,3},{1,0,3,2},{1,2,0,3},{1,2,3,0},{1,3,0,2},{1,3,2,0},{2,0,1,3},{2,0,3,1},{2,1,0,3},{2,1,3,0},{2,3,0,1},{2,3,1,0},{3,0,1,2},{3,0,2,1},{3,1,0,2},{3,1,2,0},{3,2,0,1},{3,2,1,0}};
int cp[] = {0,1,1,2,2,3,1,2,2,3,3,4,2,3,3,4,4,5,3,4,4,5,5,6};
struct node{int num,lson,rson;
}ns[100];
void init(){ns[1].lson=2;ns[1].rson=3;ns[2].lson=4;ns[2].rson=5;ns[3].lson=6;ns[3].rson=7;ns[8].lson=9;ns[8].rson=10;ns[9].lson=11;ns[9].rson=12;ns[11].lson=13;ns[11].rson=14;ns[15].lson=16;ns[15].rson=17;ns[16].lson=18;ns[16].rson=19;ns[19].lson=20;ns[19].rson=21;ns[22].lson=23;ns[22].rson=24;ns[24].lson=25;ns[24].rson=26;ns[25].lson=27;ns[25].rson=28;ns[29].lson=30;ns[29].rson=31;ns[31].lson=32;ns[31].rson=33;ns[33].lson=34;ns[33].rson=35;
}
void tree_fill(int rt,int i,int& idx,int& op){if(ns[rt].lson == 0 && ns[rt].rson == 0){ns[rt].num = a[ps[i][idx++]];return ;}tree_fill(ns[rt].lson,i,idx,op);ns[rt].num = -(op%4)*1000 - 1000;op /= 4;tree_fill(ns[rt].rson,i,idx,op);
}
int calc(int rt,int &cost){if(ns[rt].lson == 0 && ns[rt].rson == 0) return ns[rt].num;if(ns[rt].num == -3000 || ns[rt].num == -4000){if(ns[ns[rt].lson].num == -1000 || ns[ns[rt].lson].num == -2000) cost ++;if(ns[ns[rt].rson].num == -1000 || ns[ns[rt].rson].num == -2000) cost ++;}int l = calc(ns[rt].lson,cost);int r = calc(ns[rt].rson,cost);if(l == -1000 || r == -1000) return -1000;switch(ns[rt].num){case -1000:return l+r;case -2000:return l-r;case -3000:return l*r;case -4000:if(r == 0 || l % r != 0) return -1000;return l / r;}
}
int mi = 1000;
int main(){init();cin>>a[0]>>a[1]>>a[2]>>a[3];for(int t = 0;t < 5;++t)for(int i = 0;i < 24;++i){for(int j = 0;j < 64;++j){int idx = 0,op = j,cost = 2*cp[i];tree_fill(t*7+1,i,idx,op);int res = calc(t*7+1,cost);if(res == 24) mi = min(mi,cost);}}if(mi == 1000) puts("impossible");else printf("%d\n",mi);
}