[dfs+组合数学] Codeforces Round #491 (Div. 2) E. Bus Number

题目链接

E. Bus Number

分析

题解,官网已经有啦,我就不详细写了。对于每种数字,就算他的个数,那么原题就转化为每种数字至少出现一次并且不包含前导0的排列个数了,枚举(dfs)出每种数字的出现个数,然后就算组合出的不包含前导0的数的个数,

后一个问题见这篇blog给定每种数字的个数计算不包含前导0的数的个数

前一个问题就是直接dfs,我昨晚打比赛时,出了点错误有啦重复枚举,见我代码

void solve(){
    string s;
    for(int i=0 ; i<10 ; ++i)
        for(int j=1 ; j<=cnt[i] ; ++j)
            s+= i;
    //if(was.count(s))return;
    //was.insert(s);
    ans+= cal_cnt();
    for(int i=0 ; i<10 ; ++i){
        if(cnt[i]<=1)continue;
        cnt[i]--;
        solve();
        cnt[i]++;
    }
}

这种搜索最易出现重复状态,不过也是可以避免的,就用个set维护所有状态就好,这给我一个启示在出现这种bug的时候应该用set维护状态测试是否出现重复枚举。

那么有没有不包含重复枚举的方法呢

有,这样就好

void print(int* state){
    for(int i=0 ; i<10 ; ++i)cout << state[i] <<" ";
    cout<<endl;
    cout.flush();
}

void dfs(int i){
    if(i==10){
        //calculate
        ans += cal_cnt(now_state);
//      print(now_state);
    }else{
        if(cnt[i]>0){
            for(int j=1 ; j<=cnt[i] ; ++j){
                now_state[i] =j;
                dfs(i+1);
            }
        }else dfs(i+1);
    }
}

因为now_state是直接赋值存储的当前状态,所以不用再在更改什么了。

AC code

#include <bits/stdc++.h>
using namespace std;

#define MAXN 200
const double eps = 1e-8;
typedef long long LL;
int cnt[10];
int now_state[10];
LL fact[30];
LL ans=0;
inline LL cal_cnt(int *state){
    LL n=0;
    for(int i=1 ; i<10 ; ++i)n += state[i];
    LL ret = fact[n];
    for(int i=1 ; i<10 ; ++i)ret /=fact[state[i]];
    LL tmp =1;
    if(cnt[0]>0){
        tmp = fact[n+state[0]-1]/fact[state[0]]/fact[n-1];
    }
    return ret*tmp;
}

set<string> was;

//void solve(){
//    string s;
//    for(int i=0 ; i<10 ; ++i)
//      for(int j=1 ; j<=cnt[i] ; ++j)
//          s+= i;
//    if(was.count(s))return;
//    was.insert(s);
//    ans+= cal_cnt();
////    std::cout << ans << '\n';
//    for(int i=0 ; i<10 ; ++i){
//        if(cnt[i]<=1)continue;
//        cnt[i]--;
//        solve();
//        cnt[i]++;
//    }
//}

void print(int* state){
    for(int i=0 ; i<10 ; ++i)cout << state[i] <<" ";
    cout<<endl;
    cout.flush();
}

void dfs(int i){
    if(i==10){
        //calculate
        ans += cal_cnt(now_state);
//      print(now_state);
    }else{
        if(cnt[i]>0){
            for(int j=1 ; j<=cnt[i] ; ++j){
                now_state[i] =j;
                dfs(i+1);
            }
        }else dfs(i+1);
    }
}


int main(int argc, char const *argv[]) {
     ios_base::sync_with_stdio(0);
     cin.tie(0);
    string s;
    fact[0]=1;
    for(int i=1 ; i < 20 ; i++)fact[i] = fact[i-1]*i;
    cin>>s;
    memset(cnt,sizeof(cnt),0);
    for(int i=0 ; i< s.size() ; ++i)
        cnt[s[i]-'0']++;
    dfs(0);

    std::cout << ans << endl;
//    cout.flush();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dylan_frank/article/details/80792578