P1118 [USACO06FEB] Backward Digit Sums G/S

我理解的题目意思

给两个正整数 n,sum 。将数字从 1 到 n 按某种顺序写下来,然后将相邻的数字相加,得到一个数字更少的新列表,重复这个过程,直到只剩下一个数字,若这个数字等于sum,则输出满足这个条件的字典序最小的序列1~n;否则不输出。

$$1≤N≤12,1≤sum≤12345$$

解题思路

数组ai每次相邻相加的过程,最终结果的系数就是杨辉三角的对应行。所以先预处理出c记录杨辉三角系数,再进行深度优先搜索尝试所有顺序,设置一个pos,按字典序尝试数字填入a[pos],结合剪枝优化时间,在字典序尝试之前先判断已经填入的 a[i]*c[i] 之和是否大于sum,大于则停止搜索。当pos等于n时,判断 a[i]*c[i] 之和是否等于sum。

代码:

#include <iostream>
#include <algorithm>
using namespace std;

int n, sum;
int a[15],c[15];

bool vis[15];

void ini(){
    for(int i=0;i<n;i++){
        c[i]=1;
        for(int j=1;j<=i;j++){
            c[i]=c[i]*(n-j)/j;
        }
    }
}

int calc(){
    int res=0;
    for(int i=0;i<n;i++){
        res+=a[i]*c[i];
    }
    return res;
}

bool dfs(int pos){
    if(pos==n)return calc()==sum;

    int csum=0;
    for(int i=0;i<pos;i++){
        csum+=a[i]*c[i];
        
    }
    if(csum>sum)return false;

    for(int i=1;i<=n;i++){
        if(!vis[i]){
            vis[i]=true;
            a[pos]=i;
            if(dfs(pos+1))return true;
            vis[i]=false;
        }
    }
    return false;

}



int main()
{
    cin >> n >> sum;
    ini();
    if(dfs(0)){
        for(int i=0;i<n;i++){
            cout<<a[i]<<" ";
        }
    }
    return 0;
}