2021-04-06

洛谷P1118 [USACO06FEB]Backward Digit Sums G/S

习题地址:https://www.luogu.com.cn/problem/P1118

题目大意:给你一个n和一个sum,要求出1~n的字典序最小的一个全排列,使其如图进行相加求和到只剩一个数,如果最后这个数等于sum则输出这个全排列,否则什么也不输出,在这里插入图片描述
思路:
我们举例相加,显然发现最后剩下的一个数前面的系数有点眼熟,不就是杨辉三角形的某一行吗,也就是杨辉三角形第n-1行的系数,所以我们可以写个dfs将1~n的全排列从小到大一个一个枚举看是否满足,如果满足就输出,求杨辉三角形我们可以使用递推,公式:在这里插入图片描述
求全排列时我们需要进行一些优化,开始没有优化就超时了,那要怎么优化呢?当一个排列还没由枚举完全时如果发现相加已经大于sum了那么改全排列一定不能满足了,所以剪枝掉,另外求全排列时进行回溯就ok了。
在这里插入图片描述
下面看代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
typedef long long ll;
using namespace std;
int zuhe[13][13],vit[25],flag=1;
//zuhe[][]放的是杨辉三角形,vit[]是回溯法的辅助数组
//因为可能有多种情况满足,所以设个标志位
//使其之前输出字典序最小的哪一种情况
void creat_zuhe()
{
    for(int i=0; i<=12; i++)
    {
        zuhe[i][0]=1;
        for(int j=1; j<=i; j++)
        {
            zuhe[i][j]=zuhe[i-1][j-1]+zuhe[i-1][j];
            //递推求杨辉三角形,其实如过只求杨辉三角形的
            //一行还有跟简单的方法。
        }
    }
}
void dfs(int n,int sum,int *arr,int cur,int kk,int cc)
{
    if(kk>sum)return;//剪枝
    if(cur==n)
    {
        if(kk==sum)
        {
            for(int i=0; i<n; i++)
                cout<<arr[i]<<' ';//输出结果
            cout<<endl;
            flag=0;//设标志位防止输出多个
        }
        return;
    }
    vit[cc]=1;//表示这个数已经用过
    for(int i=1; i<=n; i++)
    {
        if(!vit[i]&&flag)
        {
            arr[cur]=i;
            dfs(n,sum,arr,cur+1,kk+zuhe[n-1][cur]*arr[cur],i);
            //进行递归
        }
    }
    vit[cc]=0;//记得复原以便下次使用
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    creat_zuhe();
    int n,sum,arr[10000];
    cin>>n>>sum;
    dfs(n,sum,arr,0,0,0);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值