问题描述:
给定一个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
思路:
我们在输入中发现所有的数(前后两两相加)的结果是16,而得到的输入结果是1,2,3,4可能存在的排列次序。
我们输入的第一个数字则代表从1开始(按照每次自增1)往后存储到你输入的这个数字到数组中去。
然后在循环中通过 arr1[k] = arr1[k] + arr1[k+1] 是数组元素两两相加判断是否为sum.
在这里我选择了dfs(深度遍历)的方式来进行暴力枚举,把每一种情况都求sum一遍直到找到目标后才退出。首先把step设置为0,先到达最深处,比如题目中的是4。然后再逆向返回一个个来测试,先把遍历的标记为1,如:4和3,4和2,4和1,依次类推。待这种情况结束后,又赋值为0.
完整代码:
import java.awt.*;
import java.util.Scanner;
public class Main {
public static int n;
public static int sum;
public static boolean isFlag = true;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
sum = scan.nextInt();
int step = 0;
int[] arr = new int[n];
int[] vit = new int[n+1];
dfs(step,arr,vit);
}
public static void dfs(int step,int[] arr, int[] vit){
if (step == n){
int[] arr1 = new int[n];
for (int i = 0; i < arr.length;i++){
arr1[i] = arr[i];
}
for (int j = 1; j < n; j++){
for (int k = 0; k < n-j; k++){
arr1[k] = arr1[k] + arr1[k+1];
}
}
if (arr1[0] == sum){
for (int x : arr){
System.out.print(x + " ");
}
isFlag = false;
return;
}
}
if (isFlag){
for (int i = 1; i <= n; i++){
if (vit[i] == 0){
arr[step] = i;
vit[i] = 1;
dfs(step+1,arr,vit);
vit[i] = 0;
}
}
}
return;
}
}