UVa 10344 算23点

来源:互联网 发布:qq群踢人软件 编辑:程序博客网 时间:2024/05/29 18:01

题意:有5个数,3种运算符:加、减、乘,用全部5个数,和4个运算符,构成一个表达式,使得值为23,这里没有运算符的优先级,全部是从左往右算。是可以这么理解,题目给的是从左到右依次打了括号。

思路:这里是对表达式的位置进行dfs。可以看到第0位是数字,第1位是运算符,依次则,偶数位是数字,奇数位是运算符。dfs中把当前位置cur分为奇偶分别处理。偶数位置时,则对数字进行枚举,并计算当前表达式的值,注意dfs之后的恢复;奇数位置时,枚举三种运算符。对比可以发现,枚举数字时,由于数字只能出现一次,所以用vis数组标志是否用过;枚举运算符时,由于运算符可多次使用,所以直接枚举即可。另外,初次的dfs调用,由于a[0]前面没有运算符,可默认其为+号,所以初次以dfs(0,'+',0)调用。

还有一种方法是,对每种排列枚举运算符进行运算即可。即调用next_permutation。这里没写。我这里的方法相当于把数字和运算符混在一起进行排列。

解答树的结点个数也可以计算,5!*3^4=9720。测试后发现如果不剪枝,时间有点长。。

注意:开始的思路是在遇到运算符时进行表达式的计算,但这样如果以dfs(0,0,0)初次调用的话,则在a[0]前面也枚举了运算符,是不对的;之后把这一点改了。改成的版本,在1号位没有用,0号和2号位是数字,然后3号位枚举符号,是运算0号和2号的数字的。相当于了后缀表达式形式了。但还是有问题。。。附在最后。

这说明,开始写之前,还是要多想想;否则写出来一个挫的之后,这里发现一问题,那里发现一问题,在它的基础上缝缝补补,就把自己搞得晕头转向了,有时甚至还不如重头重新写,比如这里就是暂时放下了,重新写的,很快就好了。

这里给出一些测试数据:

input:

42 8 2 32 37 
10 43 21 46 5 
44 2 27 30 29 
10 20 20 2 36 
28 3 34 42 2
22 6 6 5 37
34 3 31 18 12
25 46 28 13 2
12 4 19 2 50
1 12 2 1 49
48 48 42 2 11
1 2 43 26 33
0 0 0 0 0

output:

Possible
Possible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible
Impossible

Code:

//AC了 #include<stdio.h>#include<string.h>bool dfs(int cur,char c,int cnt);int a[6];int vis[6];//int C[15];//char F[5];int main(){  while(scanf("%d%d%d%d%d",&a[0],&a[1],&a[2],&a[3],&a[4])==5     &&a[0]&&a[1]&&a[2]&&a[3]&&a[4])  {    memset(vis,0,sizeof(vis));    if(dfs(0,'+',0)) printf("Possible\n"); else printf("Impossible\n");  }  return 0;}bool dfs(int cur,char c,int cnt){  if(cur==9)  {    if(cnt==23)    {       return 1;    }    else return 0;  }  if(cur%2==0)  {//枚举数字     for(int i=0;i<5;++i)      if(!vis[i])      {        vis[i]=1;//选择a[i]        if(c=='+') cnt=cnt+a[i];        else if(c=='-') cnt=cnt-a[i];        else cnt=cnt*a[i];        if(dfs(cur+1,' ',cnt)) return 1;        vis[i]=0;        if(c=='+') cnt=cnt-a[i];        else if(c=='-') cnt=cnt+a[i];        else cnt=cnt/a[i];      }          }  else  {//枚举运算符      if(dfs(cur+1,'+',cnt)) return 1;     if(dfs(cur+1,'-',cnt)) return 1;     if(dfs(cur+1,'*',cnt)) return 1;        }  return 0;}
AC之后的时间是2.942s,限制是在3s内,这是擦边过啊。于是写了一个剪枝的,时间减少一半多,但还是1.275s,排在1318名。

Code:

//AC了,在上一版本上的剪枝 #include<stdio.h>#include<string.h>bool dfs(int cur,char c,int cnt);int a[6];int vis[6];//int C[15];//char F[5];int main(){  while(scanf("%d%d%d%d%d",&a[0],&a[1],&a[2],&a[3],&a[4])==5     &&a[0]&&a[1]&&a[2]&&a[3]&&a[4])  {    memset(vis,0,sizeof(vis));    if(dfs(0,'+',0)) printf("Possible\n"); else printf("Impossible\n");  }  return 0;}bool dfs(int cur,char c,int cnt){  int temps=0;  for(int i=0;i<5;++i)    if(!vis[i]) temps=temps+a[i];  if(cnt-temps>23) return 0;  //剪枝  if(cnt<0 && cnt+temps<23) return 0;   if(cur==9)  {    if(cnt==23)    {       return 1;    }    else return 0;  }  if(cur%2==0)  {//枚举数字     for(int i=0;i<5;++i)      if(!vis[i])      {        vis[i]=1;//选择a[i]        if(c=='+') cnt=cnt+a[i];        else if(c=='-') cnt=cnt-a[i];        else cnt=cnt*a[i];        if(dfs(cur+1,' ',cnt)) return 1;        vis[i]=0;        if(c=='+') cnt=cnt-a[i];        else if(c=='-') cnt=cnt+a[i];        else cnt=cnt/a[i];      }          }  else  {//枚举运算符      if(dfs(cur+1,'+',cnt)) return 1;     if(dfs(cur+1,'-',cnt)) return 1;     if(dfs(cur+1,'*',cnt)) return 1;        }  return 0;}
最初始的思路,没AC,有问题的Code:

//有问题 //思路是在主函数中枚举第0位的数字。dfs函数中忽略1号位,从2号位开始偶数位枚举数字,//奇数位枚举运算符。3号位的运算符是计算0号和2号的数字的,相当于了后缀表达式形式。//但还没有AC,还是有些问题~ #include<stdio.h>#include<string.h>bool dfs(int cur,int pre,int cnt);int a[6];int vis[6];int C[15];char F[5];int main(){  while(scanf("%d%d%d%d%d",&a[0],&a[1],&a[2],&a[3],&a[4])==5     &&a[0]&&a[1]&&a[2]&&a[3]&&a[4])  {    //if(dfs(0,0,0)) printf("Possible\n");else printf("Impossible\n");              int flag=0;    for(int i=0;i<4;++i)    {      memset(vis,0,sizeof(vis));      int cnt=a[i];      vis[i]=1;      C[0]=a[i];      if(flag=dfs(1,0,cnt)) break;    }    if(flag) printf("Possible\n"); else printf("Impossible\n");  }  return 0;}bool dfs(int cur,int pre,int cnt){  if(cur==10)  {    if(cnt==23)    {       for(int i=0;i<4;++i)        printf("%d%c",C[i],F[i+1]);      printf("%d\n",C[4]);      return 1;    }    else return 0;  }  if(cur%2==0)  {//枚举数字     for(int i=0;i<5;++i)      if(!vis[i])      {        vis[i]=1;//选择a[i]        C[cur/2]=a[i];        if(dfs(cur+1,a[i],cnt)) return 1;        vis[i]=0;      }          }  else  {//枚举运算符     if(cur==1) dfs(cur+1,0,cnt);    for(int i=0;i<3;++i)    {      if(i==0)       { cnt=cnt+pre;         F[cur/2]='+';        if(dfs(cur+1,0,cnt)) return 1; cnt=cnt-pre;}      else if(i==1)       { cnt=cnt-pre;         F[cur/2]='-';        if(dfs(cur+1,0,cnt)) return 1; cnt=cnt+pre;}      else       { cnt=cnt*pre;         F[cur/2]='*';        if(dfs(cur+1,0,cnt)) return 1; cnt=cnt/pre;}          }  }  return 0;}




0 0
原创粉丝点击