码迷,mamicode.com
首页 > 编程语言 > 详细

Enum:Backward Digit Sums(POJ 3187)

时间:2015-10-04 18:23:57      阅读:263      评论:0      收藏:0      [点我收藏+]

标签:

                  技术分享

                 反过来推

  题目大意:就是农夫和这只牛又杠上了(怎么老是牛啊,能换点花样吗),给出一行数(从1到N),按杨辉三角的形式叠加到最后,可以得到一个数,现在反过来问你,如果我给你这个数,你找出一开始的序列(可能存在多个序列,输出字典序最小的那个)。

  这一题首先你要看懂原文的那个1到N是什么意思,就是那一行数只能是1到N,而不是1到10(我一开始犯了这个愚蠢的错误,导致枚举到风扇呼呼的转),如果是这样给你,那么这道题就很简单啦,就直接是用next_permutation枚举所有的序列就可以了,然后找出字典序最小的那个。

  但是这里有个问题,如果你真的找出一个然后去比较字典序,那真是太慢了,一开始直接暴力枚举+测试一个一个字串的速度

  技术分享

  看到了没?差点就超时了,这个还是我直接用二维数组+迭代的,换暴力DFS直接就超时了吧。

  其实这个时候我们可以看到,这样做我们忽略了一个事实,如果字串是顺序的,我们可以回想一下我们的枚举是怎枚举的(STL里面也是这么写的),是一个循环从1到N,然后找到没有被标记的数,然后进去递归,这样的话,其实就隐含了字典序排序了,如果我们一开始按照12345678...这样排列下来,那么找到的第一个字串,肯定是字典序最小的,所以,我们找到之后直接break就可以了

  

 1 #include <iostream>
 2 #include <functional>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 
 7 static int set[11], tmp[11];
 8 static int sum, length;
 9 
10 void enum_string(const int,const int);
11 bool scmop(void);
12 
13 int main(void)
14 {
15     while (~scanf("%d%d", &length, &sum))
16     {
17         for (int i = 1; i <= length; i++)
18             tmp[i - 1] = i;
19         if (length == 1 && tmp[0] == sum)
20         {
21             for (int i = 0; i < length; i++)
22                 printf("%d ", tmp[i]);
23             printf("\n");
24             continue;
25         }
26         do{
27             for (int i = 0; i < length - 1; i++)
28                 set[i] = tmp[i] + tmp[i + 1];
29             for (int i = length - 2; i >= 0; i--)
30             {
31                 for (int j = 0; j < i; j++)
32                     set[j] = set[j] + set[j + 1];
33             }
34             if (set[0] == sum)
35             {
36                 for (int i = 0; i < length; i++)
37                     printf("%d ", tmp[i]);
38                 printf("\n");
39                 break;
40             }
41         } while (next_permutation(tmp, tmp + length));
42 
43     }
44     return 0;
45 }

  技术分享  

  还没完,开始我不是说了吗?这一题是按照杨辉三角的形式展开的,我们知道杨辉三角的每一行的数都是组合数Ckn,那么在数学上,杨辉三角的加法一行数的相加次数相当于这个Ckn,

    技术分享

    也就是说,我们只用把这一行的数乘以Ckn就可以得到结果了,这样做会更快

  

#include <iostream>
#include <functional>
#include <algorithm>

using namespace std;

static int set_sum, tmp[11], Cn[11];
static int sum, length;

void enum_string(const int, const int);
bool scmop(void);
void Cal_Cn(const int);

int main(void)
{
    while (~scanf("%d%d", &length, &sum))
    {
        for (int i = 1; i <= length; i++)
            tmp[i - 1] = i;
        memset(Cn, 0, sizeof(Cn));
        Cal_Cn(length);
        if (length == 1 && tmp[0] == sum)
        {
            for (int i = 0; i < length; i++)
                printf("%d ", tmp[i]);
            printf("\n");
            continue;
        }
        do{
            set_sum = 0;
            for (int i = 0; i < length; i++)
                set_sum += Cn[i] * tmp[i];
            if (set_sum == sum)
            {
                for (int i = 0; i < length; i++)
                    printf("%d ", tmp[i]);
                printf("\n");
                break;
            }
        } while (next_permutation(tmp, tmp + length));
    }
    return 0;
}

void Cal_Cn(const int length)
{
    Cn[0] = 1;
    for (int j = 1; j < length; j++)
    {
        Cn[j] = length - 1;
        for (int k = 2; k <= j; k++)
            Cn[j] *= (length - k);
        for (int k = 1; k <= j; k++)
            Cn[j] /= k;
    }
}

  技术分享

  最后,32ms

Enum:Backward Digit Sums(POJ 3187)

标签:

原文地址:http://www.cnblogs.com/Philip-Tell-Truth/p/4854761.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!