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;
}
原文地址:https://www.cnblogs.com/yefeng1627/p/2808993.html