问题:
给定一个1~N的排列a[i],每次将相邻两个数相加,得到新序列,再对新序列重复这样的操作,显然每次得到的序列都比上一次的序列长度少1,最终只剩一个数字。
例如:
3 1 2 4
4 3 6
7 9
16
现在如果知道N和最后得到的数字sum,请求出最初序列a[i],为1~N的一个排列。若有多种答案,则输出字典序最小的那一个。数据保证有解。
解决方法:递归思想。
C源码:
#include<stdio.h>
#include<string.h>
#include<math.h>
int flag = 0; //找到的满足条件为1,反之则0;
void DFS(int arry[], int visited[], int n, int index, int sum);
int main()
{
int arry[10]; //用来保存结果的数组;
int visited[11] = {
0}; //访问过置1,没访问过置0;
int n = 0;
int sum = 0;
scanf("%d %d",&n,&sum);
DFS(arry, visited, n, 0, sum);
return 0;
}
void DFS(int arry[], int visited[], int n, int index, int sum)
{
if(flag==0)
{
if(index == n) //递归出口;
{
int arry1[n]; //暂时保存找到的数组,用它来计算是否满足条件;
int j = 0;
int k = 0;
for (j = 0; j<n; j++)
{
arry1[j] = arry[j];
}
for (j = 0; j<n-1; j++) //计算
{
for( k = 0; k<n-1-j; k++) //每进行一次都要少一个数,所以要k<n-1-j;
{
arry1[k] = arry1[k]+arry1[k+1];
}
}
if(arry1[0]==sum) //检查是否满足条件
{
for ( j = 0; j<n; j++)
{
printf("%d ",arry[j]);
}
flag = 1; //满足后将flag置1,就算再有其他满足的情况也不会输出。(这里,我们最先得到的满足条件的情况就是题目中要求的字典序最小的情况)
}
}
}
int i = 0;
for(i = 1; i<=n; i++) //从1到n,一个个的去试;
{
if(visited[i] == 0) //开始访问;
{
arry[index] = i; //把1-n中不重复的数赋值给arry
visited[i] = 1; //这个数字已经访问过了,置1;
DFS(arry,visited,n,index+1,sum); //继续访问其他没有被访问的数;
visited[i] = 0; //这里1-n全部访问结束,但是不满足条件,返回上一层,并将这个数置0,表示没有被访问。
}
}
}