1. 程式人生 > >Hdu4403---A very hard Aoshu problem解題報告(DFS暴搜)

Hdu4403---A very hard Aoshu problem解題報告(DFS暴搜)

                                 A very hard Aoshu problem題目連結

Problem Description

Aoshu is very popular among primary school students. It is mathematics, but much harder than ordinary mathematics for primary school students. Teacher Liu is an Aoshu teacher. He just comes out with a problem to test his students:

Given a serial of digits, you must put a '=' and none or some '+' between these digits and make an equation. Please find out how many equations you can get. For example, if the digits serial is "1212", you can get 2 equations, they are "12=12" and "1+2=1+2". Please note that the digits only include 1 to 9, and every '+' must have a digit on its left side and right side. For example, "+12=12", and "1++1=2" are illegal. Please note that "1+11=12" and "11+1=12" are different equations.

Input

There are several test cases. Each test case is a digit serial in a line. The length of a serial is at least 2 and no more than 15. The input ends with a line of "END".

Output

For each test case , output a integer in a line, indicating the number of equations you can get.

Sample Input

1212

12345666

1235

END

Sample Output

2  

2

0

題目大意:

給你一行數字,你可以在所有數字之間自由選擇位置往其中加入 + 和 = 這兩種符號(=只能放一個),使得等式左右兩邊值相等。

例如1212 則有 1 + 2 = 1 + 2和 12 = 12兩種符合條件的情況

12345666則有1 + 2 + 3 + 4 + 56 = 66和12 + 3 + 45 + 6 = 66兩種符合情況的條件

(另外:1 + 11 = 12 和 11 + 1 = 12是兩種不同情況)

思路:

提前把每位數的所有取值情況枚舉出來

(如:1212就從1,12,121,1212,2,21一直列舉到2)

然後直接從第一位開始暴搜,把=號插入在任意數中間,=號左邊搜尋完,再搜尋右邊,左右兩邊值相等則ans++。

AC Code:

#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<list>
#define mod 998244353
#define INF 0x3f3f3f3f
#define Min 0xc0c0c0c0
#define mst(a) memset(a,0,sizeof(a))
#define f(i,a,b) for(int i = a; i < b; i++)
using namespace std;
typedef long long ll;
const int MAX_N = 20;
int len, ans;
int arr[MAX_N][MAX_N];
char s[MAX_N];
void get_val(){
    for(int i = 1; i <= len; i++){      
        for(int j = i; j <= len; j++){              //i代表數的第i位,j代表從i開始數的連續長度
            for(int t = i; t <= j; t++){            //例如:1212這個數, arr[1][1] = 1, arr[1][2] = 12
                                                    //arr[2][1] = 2, arr[2][2] = 21,arr[2][3] = 212
                arr[i][j] = arr[i][j] * 10 + (s[t] - '0'); //列舉每位數的所有可能取值情況
            }
        }
    }
}
void dfs_right(int  pos_r, int sum1, int sum2){
    if(pos_r > len){
        if(sum1 == sum2){
            ans++;
            //printf("%d\n",sum1);
        }
        return ;
    }
    for(int i = pos_r; i <= len; i++){  //右邊暴搜
        dfs_right(i + 1, sum1, sum2 + arr[pos_r][i]);
    }
}
void dfs_left(int pos_l, int sum, int pos_r){
    if(pos_l > pos_r){          //遇見了=號,開始暴搜右邊
        dfs_right(pos_r + 1, sum, 0);
    }
    for(int i = pos_l; i <= pos_r; i++){
        dfs_left(i + 1, sum + arr[pos_l][i], pos_r);
    }
}
int main(){
    int T;
    ios::sync_with_stdio(false);
    while(cin>>(s + 1)){
        if(s[1] == 'E'){
            break;
        }
        ans = 0;
        len = strlen(s + 1);
        mst(arr);
        get_val();            //列舉所有情況
        for(int step = 1; step < len; step++){
            dfs_left(1, 0, step);       //從第一位開始暴搜=號在所有位置的情況
        }
        cout<<ans<<endl;
    }
    return 0;
}