poj -1020 - Dessert (通俗易懂) (本人小白

FJ has a new rule about the cows lining up for dinner. Not only must the N (3 <= N <= 15) cows line up for dinner in order, but they must place a napkin between each pair of cows with a "+", "-", or "." on it. In order to earn their dessert, the cow numbers and the napkins must form a numerical expression that evaluates to 0. The napkin with a "." enables the cows to build bigger numbers. Consider this equation for seven cows: 
      1 - 2 . 3 - 4 . 5 + 6 . 7

This means 1-23-45+67, which evaluates to 0. You job is to assist the cows in getting dessert. (Note: "... 10 . 11 ...") will use the number 1011 in its calculation.) 
Input
One line with a single integer, N 
Output
One line of output for each of the first 20 possible expressions -- then a line with a single integer that is the total number of possible answers. Each expression line has the general format of number, space, napkin, space, number, space, napkin, etc. etc. The output order is lexicographic, with "+" coming before "-" coming before ".". If fewer than 20 expressions can be formed, print all of the expressions. 
Sample Input
7
Sample Output
1 + 2 - 3 + 4 - 5 - 6 + 7
1 + 2 - 3 - 4 + 5 + 6 - 7
1 - 2 + 3 + 4 - 5 + 6 - 7
1 - 2 - 3 - 4 - 5 + 6 + 7
1 - 2 . 3 + 4 + 5 + 6 + 7
1 - 2 . 3 - 4 . 5 + 6 . 7
6

题意:

输入一个n,在1-n两两之间依次插入一个运算符——‘+’,‘-’,‘.’,3.4 代表整型34。依次运算,统计结果为0的不同表达式,结果大于20,只用输出前20个表达式,最后一行还要输出符合条件的表达式的总数。运算符的优先级:‘+’>‘-'  >  '.'  。

题解:

DFS深搜,如果运算符是  '.'  就需要改变上一次的运算,因此要标记前一次计算结果sum和前一次的运算值cur(加了多少或减了多少)。

AC代码:

#include<iostream>
#include<cmath>
#include<math.h>
#include<cstdio>
using namespace std;
char arr[100];                    //表达式数组
char op[3]={'+','-','.'};
int num[30],n,ans,p,cur,sum;      //P代表表达式数组的移动
void dfs(int x,int cur,int sum)   //x代表存储数字的数组的下标
{
    if(!sum&&x==n-1)             //和为0且用了1-N
    {
        ans+=1;
        if(ans>20) return;     
        cout<<arr[0];
      for(int q=1;q<p;q++)
      {
          int r=arr[q]-'0';     //这样是为了存储时直接存两位数为一个字符
          if(r>=10)             //判断是不是两位数
            cout<<" "<<num[r-1];
          else cout<<" "<<arr[q];
      }
      cout<<endl;
        return ;
    }
    if(x==n-1) {               //到达边界
            return ;
    }
    for(int i=0;i<3;i++)       //遍历三个运算符
    {
        int t=sum,b=cur;       //存储sum和cur,回溯时带换回来(因为sum和cur都要更新)
        if(i==0)
            sum=sum+num[x+1],cur=num[x+1];  
        if(i==1)
            sum=sum-num[x+1],cur=-num[x+1];//更新sum和cur
         if(i==2){
            int dp;
            if(x+1>8) dp=2;                //判断下一位要运算的数的位数
            else dp=1;
            int tep=abs(cur)*pow(10*1.0,dp);
            if(cur>0)
            {
                sum=sum-cur+tep+num[x+1];   //上一次是加了一个数,先减去家的数,再加上新的数;
                    cur=tep+num[x+1];       //更新cur为加得的新的数
            }
            else
            {
                sum=sum-cur-tep-num[x+1];   //上一次是减,更新就相反
                    cur=-tep-num[x+1];
            }
        }
        arr[p++]=op[i];                     //先存储运算符
        arr[p++]=(num[x+1]+'0');            //存储数字,无论数字是一位还是两位,都存储为一个字符,只需要在输出时处理一下
        dfs(x+1,cur,sum);                   //DFS下一个数
        sum=t;                              //回溯
        cur=b;
        p-=2;                               //答案数组回溯两位,因为上面存了两次
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
        num[i]=i+1;                       //存储1-N
        sum=1;                            //先把第一位数加起  
        arr[0]='1',p=1;                       //表达式第一位永远是1,p移到1
        dfs(0,1,1);
         cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/qq_41157137/article/details/80920193
今日推荐