acdream 1014: Dice Dice Dice DFS枚举

1014: Dice Dice Dice

Time Limit: 10 Sec   Memory Limit: 128 MB 

Description

There are 1111 ways in which five 6-sided dice (sides numbered 1 to 6) can be rolled so that the top three numbers sum to 15. Some examples are: 
 
D1,D2,D3,D4,D5 = 4,3,6,3,5 
D1,D2,D3,D4,D5 = 4,3,3,5,6 
D1,D2,D3,D4,D5 = 3,3,3,6,6 
D1,D2,D3,D4,D5 = 6,6,3,3,3 
 
Now we have a extended problem:
In how many ways can n m-sided dice (sides numbered 1 to m) be rolled so that the top k numbers sum to p?

 

Input

There are multiple test cases. (about 15 groups)
For each test case, there is only four integers n, m, k, p. (1 <= k <= n <= 20, 3 <= m <= 12)
 

 

Output

For each test case, output an integer indicating the answer.

 

Sample Input

5 6 3 15 6 6 3 15

Sample Output

1111 7770

HINT

 

Source

dut200901102

题目大意: 一个m面的骰子,抛n次,得到序列。统计其中k次最大的和为p的序列数。

解题思路:直接枚举序列,时间总共需要n^m = pow(20,12), 这样时间上不符合。

                  通过枚举m个值出现的次数,来降低时间复杂度。

     因为k,n,m的值都比较小,我们可以在区间[m,1]中枚举出k个满足和为P的序列的个数,且其中最小值为x,然后再在区间[x,1]枚举出n-k个数的数量。

     最后得出[1,m]区间各个数出现的次数,则当前合法序列其排列数为  n! / { num1!*num2!*..*numM! } (其中num>0)  

View Code
#include<stdio.h>

#include<stdlib.h>

#include<math.h>

#include<string.h>

typedef long long LL;



int num[30], cnt[30], size[30];

int n, m, K, P;

LL fac[21] = {0,1}, ans;

void GetFact(){

    for(int i = 2; i <= 20; i++)

        fac[i] = fac[i-1]*i;

//    for(int i = 1; i <= 20; i++)

//        printf("%d: %lld\n", i, fac[i]);

}



void dfs_NK( int x , int CurNum , int MaxNum )

{

    if( CurNum == MaxNum )

    {

        LL res = fac[n];    

        for(int i = m; i > 0; i--)

        {

            int t = num[i]+cnt[i];

            if( t > 0 )    res /= fac[t];    

        }    

        ans += res;    

    }

    else{

        for(int i = 0; x > 0 && i <= MaxNum-CurNum; i++)

        {

            cnt[x] = i;

            dfs_NK( x-1, CurNum+i, MaxNum );    

            cnt[x] = 0;     

        } 

    }

}

void dfs_K( int x, int CurNum, int CurSum)

{

//    printf("CurNum = %d\n", CurNum);

    if( CurNum == K && CurSum == P ){

/*        for(int i = m; i > 0; i--)

        {

            printf("num[%d] = %d,", i, num[i]);

        }    

        printf("\n");*/    

        memset( cnt, 0, sizeof(cnt));    

        dfs_NK( x+1, 0, n-K );

        return;

    }

    for(int i = 0; x > 0 && i <= K-CurNum; i++)

    {

        if( CurNum + i <= K && CurSum + i*x <= P )

        {

            num[x] = i;

            dfs_K( x-1, CurNum+i, CurSum+i*x );

            num[x] = 0;    

        }     

    }

}



int main(){

    GetFact();

    while( scanf("%d%d%d%d",&n,&m,&K,&P) != EOF)

    {

        if( ceil(1.*P/m) > K ) printf("0\n");

        else{

            ans = 0;    

            memset( num, 0, sizeof(num));    

            dfs_K( m, 0, 0 );      

            printf("%lld\n", ans);    

        }

    }

    return 0;

}

 

你可能感兴趣的:(DFS)