给定整数M和N(N>=M>=1),输出所有满足M个正整数和是N的情况,并且满足A<0>≧A<1>≧...A<M-1>≧1。

网上有很多类似的问题,这个问题是一次面试前的代码手写题。简单的思路是:

  • 由于数字按照由大到小的顺序,所以第一个数最大,要满足这个要求,A<0>必须≧N/M,如果不能整除,A<0>≧(N/M)+1;
  • 所有数字最小是1,所以A<0>最大值是N-M+1;
  • 递归找出(M-1, N-A<0>)的组合;
//辅助打印数组内容
void m_print(int *arr)
{
    int i = 0;
    while(arr[i])
    {
        printf("%d ", arr[i++]);
    }
    printf("\n");
}
/*求解组合,递归求解剩余数值的组合情况
 *m - 整数个数
 *n - 所有数的和
 *mx - 所有数最大取值
 *arr - 组合保存的数组
 *s - 当前求出的数值在数组中保存的位置
 */
int func(int m, int n, int mx, int *arr, int s)
{
    int i, mi, ma;
    int marr[10] = {0};
    //在求得合适的数值前,原有数组不应该修改,将整个数组拷贝
    memcpy(marr, arr, (m+s)*sizeof(int));
    //m > n 肯定不存在解
    if (m > n)
        return 0;
    //m == n ,所有数只能是1
    if (m == n)
    {
        for (i = s; i < m+s; i++)
        {
            marr[i] = 1;
        }
        m_print(marr);
        return 0;
    }
    //1 == m, 只有n一个
    if (1 == m)
    {
        if ( n <= mx)
        {
            marr[s] = n;
            m_print(marr);
        }
        return 0;
    }
    //计算可用数的范围
    mi = n/m + ((n%m != 0)?1:0);
    ma = mx > (n-m+1)?(n-m+1):mx;
    for (i = mi; i <= ma; i++)
    {
        memset(marr, 0, (m+s)*sizeof(int));
        memcpy(marr, arr, (m+s)*sizeof(int));
        marr[s] = i;
        //递归求解所有可能组合
        func(m-1, n-i, i, marr, s+1);
    }
    return 0;
}

int foo(int m, int n)
{
    int marr[10] = {0};
    int min, max, i;
    printf("----m = %d,n = %d----\n", m, n);
    if (m > n)
        return 0;
    if (n == m)
    {
        for(i = 0; i < m; i++)
        {
            printf("1 ");
        }
        printf("\n");
        return 0;
    }
    if (1 == m)
    {
        printf("%d\n", n);
        return 0;
    }
    min = n/m + ((n%m != 0)?1:0);
    max = n - m + 1;
    
    for (i = min; i <= max; i++)
    {
        marr[0] = i;
        func(m-1, n-i, i, marr, 1);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zccblogs/p/9133217.html
今日推荐