POJ 3187 杨辉三角+枚举排列 好题

如果给出一个由1~n组成的序列,我们可以每相邻2个数求和,得到一个新的序列,不断重复,最后得到一个数sum,

现在输入n,sum,要求输出一个这样的排列,如果有多种情况,输出字典序最小的那一个。

刚开始我是直接搜,tle了

然后就开始找最初的序列和最终的和有什么关系

因为最终的和sum一定是等于若干个a[1],若干个a[2],...,若干个a[n]的和

即sum=p1*a1+p2*a2+...+pn*an

所以我们只要求出数组a的系数,n个p即可。

然后发现,和杨辉三角有很大的关系。

如果杨辉三角的行数从1开始算的话,

对于某一个1~n的排列得到sum,就需要有n个系数p,发现,这n个系数就刚好是杨辉三角的第n行。

所以对于等式:sum=p1*a1+p2*a2+...+pn*an

知道了n,我们就知道了n个系数p了,sum也知道

所以只要枚举1~n的排列,刚哪一个排列符合等式就ok了

又要字典序顺序,所以我们从小到大的顺序枚举,一有答案了,就跳出来。

 1 #include<cstdio>
 2 #include<cstring>
 3 
 4 using namespace std;
 5 
 6 const int maxn=13;
 7 int c[maxn][maxn];
 8 int a[maxn];
 9 int n,sum;
10 bool flag;
11 
12 void init_c()
13 {
14     memset(c,0,sizeof c);
15     for(int i=1;i<maxn;i++)
16     {
17         c[i][1]=1;
18         for(int j=2;j<=i;j++)
19             c[i][j]=c[i-1][j-1]+c[i-1][j];
20     }
21 }
22 
23 void solve()
24 {
25     int ret=0;
26     for(int i=1;i<=n;i++)
27     {
28         ret+=c[n][i]*a[i];
29     }
30     if(ret==sum)
31     {
32         flag=true;
33         for(int i=1;i<n;i++)
34             printf("%d ",a[i]);
35         printf("%d
",a[n]);
36     }
37     return ;
38 }
39 
40 void next(int cur)
41 {
42     if(flag)
43         return ;
44     if(cur==n+1)
45     {
46         solve();
47         return ;
48     }
49     for(int i=1;i<=n;i++)
50     {
51         int ok=1;
52         for(int j=1;j<cur;j++)
53         {
54             if(a[j]==i)
55                 ok=0;
56         }
57         if(ok)
58         {
59             a[cur]=i;
60             next(cur+1);
61         }
62     }
63 
64 }
65 
66 int main()
67 {
68     init_c();
69     while(~scanf("%d%d",&n,&sum))
70     {
71         flag=false;
72         next(1);
73     }
74     return 0;
75 }
View Code
原文地址:https://www.cnblogs.com/-maybe/p/4699593.html