资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
给定一个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
#include<iostream>
using namespace std;
int n,sum;
const int N=15;
bool flag[N];
int res[N];
bool is_end;//只需要输出一个(字典序最小的) ,用is_end判断
bool check(){
int temp[n];
for(int i=0;i<n;i++){
temp[i]=res[i];
}
int count=n-1;
while(count--){
for(int i=0;i<n-1;i++){
temp[i]=temp[i]+temp[i+1];
}
}
if(temp[0]==sum){
return true;
}else{
return false;
}
}
void dfs(int u){//u:目前使用了几个数字,处于树的第几层
if(u==n&&check()){
is_end=true;
for(int i=0;i<n;i++){
printf("%d ",res[i]);
}
printf("\n");
}
for(int i=1;i<=n;i++){
if(is_end){
break;
}
if(!flag[i]){
res[u]=i;
flag[i]=true;
dfs(u+1);
flag[i]=false;
}
}
}
int main(){
scanf("%d%d",&n,&sum);
dfs(0);
return 0;
}
思路:使用dfs算法对1~n的数进行全排列。check为限制条件:相邻两个数相加,直到只剩下一个数,这个数要与sum相等。由于全排列的字典序顺序就是从小到大的,因此第一个满足题目的字典序就是最终答案。
dfs全排列:u表示目前使用了多少个数字,一开始没有使用,因此dfs(0)。
以下红框中的判重数组为什么又要设置为false呢?
因为dfs需要回溯:
如果没有回溯,当n=5时,最终输出的全排列结果只有一个:1 2 3 4 5,因为没有flag[i]=false,1~5的flag都为true,即都不能再用了,无法进入if语句。
以下为纯全排列算法(在此基础上加check()函数和is_end即为本题的答案):
#include<iostream>
using namespace std;
int n;
const int N=15;
bool flag[N];
int res[N];
void dfs(int u){//u:目前使用了几个数字,处于树的第几层
if(u==n){
for(int i=0;i<n;i++){
printf("%d ",res[i]);
}
printf("\n");
}
for(int i=1;i<=n;i++){
if(!flag[i]){
res[u]=i;
flag[i]=true;
dfs(u+1);
flag[i]=false;
}
}
}
int main(){
scanf("%d",&n);
dfs(0);
return 0;
}