问题:
给定一个1~N的排列a[i],每次将相邻两个数相加,得到新序列,再对新序列重复这样的操作,显然每次得到的序列都比上一次的序列长度少1,最终只剩一个数字。
例如:
3 1 2 4
4 3 6
7 9
16
现在如果知道N和最后得到的数字sum,请求出最初序列a[i],为1~N的一个排列。若有多种答案,则输出字典序最小的那一个。数据保证有解。输入格式
第1行为两个正整数n,sum
输出格式
一个1~N的一个排列
样例输入
4 16
样例输出
3 1 2 4
数据规模和约定
0<n<=10
思路解析:
这个问题在于排列出n个数的所有情况,然后按照题目要求以此判断是否符合条件,全排序可运用深度优先搜索算法 (DFS),一条路走到底。每排列出n个数便进行条件判断,代码中附有详情解释。再者运用dp数组,记录每次排序后的数值,方便进行条件判断。
此题的重点在于是否掌握全排列算法,即深度优先搜索(DFS),如果不懂还得去学习理解,这样便能轻松解决这道问题。
代码:
#include<iostream>
using namespace std;
#define N 11
int n;
int sum;
int dp[N];
int used[N] = {0}; //标志数字是否被使用,0未使用,1已使用
void DFS(int step) {
/*
传进来之前进行step判断,是否已经刚好列出了n个数,
然后运动dp数组进行依次求和,判断是否等于sum,若等于则找到
*/
if (step == n + 1) {
//新声明个数组,防止在相加时破坏原数组(dp)内的值
int s[N];
//将dp[]的值拷贝到s[]里
for (int i = 1; i <= n; i++) {
s[i] = dp[i];
}
for (int i = 1; i < n; i++) { //进行 n-1 次相加
for (int j = 1; j < n - i + 1; j++) { //每一次相加所相加的次数
s[j] += s[j + 1];
}
}
if (s[1] == sum) {
for (int i = 1; i <= n; i++) {
cout << dp[i] << " ";
}
exit(0); //找到最小值,正常退出程序
}
else
{
return; //返回上一级DFS
}
}
for (int i = 1; i <= n; i++){
if (used[i] == 0) {
dp[step] = i; //将i存入第step个数
used[i] = 1; //记录已使用
DFS(step + 1);
used[i] = 0; //回收i,标记未使用,以便后面排序重新使用i
}
}
return; //回溯,返回上一级DFS
}
int main() {
cin >> n >> sum;
DFS(1);
return 0;
}
运行结果:
PS:学习就是进步,Love 😘