Hdu2212 dfs (搜索&剪枝or打表)


其实可以用搜索做。

3628800=10*fact(9)   就是这个dfs数的上限。

总体思想:搜索+剪枝,先搜出所有各位阶乘和的位数和本身位数相同的数,然后再仔细判断。

我觉得练习的时候就尽量不要用直接打表法做了吧。。

#include"stdio.h"
#include"stdlib.h"
#include"time.h"
#include"math.h"
#include"iostream"
#include"string.h"
#include"algorithm"
#include"vector"
#include"string"
#include"queue"
#include"map"

#define nmax 1000000
#define inf 0x7ffffff
#define eps 1e-8
#define PI 3.1415926535
#define PRIME 9999991
#define LL long long
///---rand---///
//double random(){return (double)(rand()%RAND_MAX )/RAND_MAX ;}
//int random(int a,int b){return (double)a+random()*(b-a+1);}
///----------///
inline int maxy(int a,int b){return a>b?a:b;}
inline int miny(int a,int b){return a<b?a:b;}
inline long long  maxy(long long  a,long long  b){return a>b?a:b;}
inline long long  miny(long long  a,long long  b){return a<b?a:b;}
using namespace std;

map<long long ,int >mp;
//LL max_int =2147483647;
LL max_int=10000000000000ll;

LL fact[20]={1,1,2,6,24,120,720,5040,40320,362880};
LL dig[20]={0ll,1ll,10ll,100ll,1000ll,10000ll,100000ll,1000000ll,10000000ll,100000000ll,1000000000ll,10000000000ll,
100000000000ll/*12*/,1000000000000ll/*13*/,10000000000000ll/*14*/};

bool is_dfs(LL v){
    LL rem=v;
    LL ans=0;
    while(v>0){
        ans+=(LL)fact[v%10];
        if(ans>rem)return false;
        v/=10;
    }
    if(ans==rem)return true;
    return false;
}

int stk[20];
int cnt;
LL ans[nmax];

void dfs_tranc(int k,LL cursum,int len){
    if(k==len){
        if(cursum>=dig[len]&&cursum<dig[len+1]&&mp[cursum]==0){//位数是否符合要求
            //is a len number.
            mp[cursum]++;
            if(is_dfs(cursum))
            ans[cnt++]=cursum;
        }
    return ;}

    if(cursum+(LL)len-k>=dig[len+1]||(LL)cursum+(LL)(len-k)*fact[9]<dig[len])return ;//剪枝

    int i;
    for(i=0;i<=9;i++){
        //if(k==0&&i==0)continue;
        dfs_tranc(k+1,(LL)cursum+fact[i],len);
    }

}

int main(){

    int i;
    cnt=0;
    mp.clear();
    //long st=clock();

    for(i=1;i<=7;i++){
        dfs_tranc(0,0,i);
    }
    
    for(i=0;i<cnt;i++){
        printf("%I64d\n",ans[i]);
    }
    //printf("Time:%ld\n",clock()-st);

return 0;}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值