Enum:Backward Digit Sums(POJ 3187)

                  

                 反过来推

  题目大意:就是农夫和这只牛又杠上了(怎么老是牛啊,能换点花样吗),给出一行数(从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("
");
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("
");
39                 break;
40             }
41         } while (next_permutation(tmp, tmp + length));
42 
43     }
44     return 0;
45 }

    

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

    

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

  

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

  

  最后,32ms

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