题目链接: www.luogu.com.cn/problem/P11…
总的思路就是DFS,不过需要注意剪枝,否则会超时。
手写了a, ab, abc, abcd后发现,最后的倒三角形和的系数是有规律的,看了题解才想起来就是杨辉三角形的第n行,由此可以先把第n行的杨辉三角打表打出来,然后DFS每进入一层就判断当前结果是否已经超出sum,超出就直接返回了。
杨辉三角的第n行第m个数 = C(n-1,m-1),可以根据组合数公式算,这题n不算大,可以硬算。不过看了题解还可以这样算:C(n,r) = [(n-r+1) / r] * C(n, r-1); 具体的可以自己推导一下。这样就可以根据前一个数推出后一个数,起始边界是1,而且杨辉三角是对称的,算一半就可以了。
AC代码:
#include<iostream>
using namespace std;
int n, sum;
int a[15];
int yanghui[15];
int vis[15];
void dfs(int cur);
int judge(int cnt);
bool flag = false;
int main(void)
{
cin >> n >> sum;
//构造第n行的杨辉三角
yanghui[1] = yanghui[n] = 1;
for(int i = 2; i <= n/2; i++)
yanghui[i] = yanghui[n+1-i] = (n-i+1) * yanghui[i-1] / (i-1);
if(n & 1 && n != 1)
yanghui[n/2+1] = (n/2+1) * yanghui[n/2] / (n/2);
dfs(1);
return 0;
}
void dfs(int cur)
{
if(cur == n+1){
if(judge(n) == sum){
for(int i = 1; i < n; i++)
cout << a[i] << " ";
cout << a[n] << endl;
flag = true;
return;
}
}
if(flag)
return;
if(judge(cur-1) > sum)
return;
for(int i = 1; i <= n; i++)
{
if(flag)
return;
if(vis[i])
continue;
a[cur] = i;
vis[i] = 1;
dfs(cur+1);
vis[i] = 0;
}
}
int judge(int cnt)
{
int res = 0;
for(int i = 1; i <= cnt; i++)
res += yanghui[i] * a[i];
return res;
}