问题描述:
娜娜是一个特别可爱的女孩子,作为学神的她最近在情感方面出现了一点点小问题。
她暗恋的琦琦是一名学霸,他只喜欢长得漂亮和学习很好的女生。
娜娜学习确实很神,但是她在琦琦面前却总是表现不出平时的神力。
琦琦感受到了娜娜对他的爱,但是他还是觉得娜娜的学习并不是特别好,于是他出了一道题给娜 娜。
“娜娜,我们之间的关系需要在不断深入的同时保持一定的平衡,不可以你总是强势或者我总是弱势。”
琦琦给了娜娜一些两两不等的数,希望娜娜能把这些数分成两组A和B,满足以下条件:
1:每一次只能操作一个数,即只取出一个数分入A中或B中;
2:每一次操作完成后,A中数之和与B中数之和的差不能超过r。
新时代的丘比特们啊,帮帮娜娜吧!
输入格式:
输入共两行。
第一行包括两个正整数n和r,n表示琦琦一共给了n个数,r的意义见题目描述。
第二行包括n个正整数,分别表示琦琦给的n个数。
输出格式:
输出共两行,分别把A与B两组数按从小到大输出。
注意输入中n个数的第一个必须分入A组。
琦琦保证这样的输出唯一。
样例输入:
4 10
9 6 4 20
样例输出:
4 6 9
20
样例说明:
先把4和6先后分入A组,再把20分入B组,最后把9分入A组。
数据规模和约定:
很小,真的很小。
思路:
本题使用dfs算法进行遍历,下面以本题的例子结合代码进行分析
dfs算法实际上是递归的思想,因此我们先来分析终止递归的算法
if (find){
return;
}
if (key >= n){
if (flag){
for (Object i : A){
System.out.print(i + " ");
}
System.out.println();
for (Object i : B){
System.out.print(i + " ");
}
find = true;
}
return;
}
当我们把A,B列表通过加强for循环输出后边将find赋值为真,这样当我们会到上一层的递归时就不会执行if(key >=n)的判断,而是直接执行完if(find)即可。而flag主要是需要满足题目的要求:需要输入的第一个元素必须放置到A列表中。
下面我们来分析dfs的主要逻辑代码!!!!~
for (int i = 0; i < n; i++){
if (!vit[i]){
if (abs(sumA + ori[i] - sumB) <= r){
A.add(ori[i]);
sumA += ori[i];
vit[i] = true;
if (ori[i] == num1){
flag = true;
}
dfs(key + 1);
A.remove(A.size()-1);
sumA -= ori[i];
vit[i] = false;
if (ori[i] == num1){
flag = true;
}
}
if (abs(sumB + ori[i] - sumA) <= r){
B.add(ori[i]);
sumB += ori[i];
vit[i] = true;
dfs(key + 1);
B.remove(B.size()-1);
sumB -= ori[i];
vit[i] = false;
}
}
}
首先如果我们想要使用dfs算法,那就必须得具好一个与储存数据数组大小相同的布尔类型的数组。这样每当我们进行递归操作时对应每次的for循环我们就可以知道上一层dfs方法对数组元素是否有遍历或者调用过。根据题目的条件我们可以得出以下的结论:
sumA + ori[i] - sumB <= r 说明这个数可以存放到A列表中
sumB + ori[i] - sumA) <= r 说明这个数可以存放到B列表中
不难发现,在存放A和B的列表中,都可以看到调用dfs递归的身影,以本例题的输入为列,在原数组已经从小到大排好序之后。我们知道9是存入到B列表中去了,而到递归进入dfs对下一个元素20进行判断时,发现两个if都不满足条件。因此我们回到上一层,把这个元素清理出B列表,然后把该元素9对应位置的布尔值赋值为false。此时i的值为2,因此当再次判断是否满足A列表的条件中,这个数就存入到A列表中去了。对于B列表也是如此的道理。
对于abs方法,我这里是使用了位运算的法则,嫌麻烦的话可以直接调用Math.abs()方法
public static int abs(int a){
return a + (a >> 31) ^ (a >> 31);
}
完整代码:
import java.util.*;
public class Main {
static int num1,sumA,sumB,n,r;
static boolean flag = false,find = false;
static List A;
static List B;
static boolean[] vit;
static int[] ori;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
r = scan.nextInt();
vit = new boolean[n];
ori = new int[n];
A = new ArrayList();
B = new ArrayList();
for (int i = 0; i < n; i++){
ori[i] = scan.nextInt();
}
num1 = ori[0];
Arrays.sort(ori);
dfs(0);
}
public static void dfs(int key){
if (find){
return;
}
if (key >= n){
if (flag){
for (Object i : A){
System.out.print(i + " ");
}
System.out.println();
for (Object i : B){
System.out.print(i + " ");
}
find = true;
}
return;
}
for (int i = 0; i < n; i++){
if (!vit[i]){
if (abs(sumA + ori[i] - sumB) <= r){
A.add(ori[i]);
sumA += ori[i];
vit[i] = true;
if (ori[i] == num1){
flag = true;
}
dfs(key + 1);
A.remove(A.size()-1);
sumA -= ori[i];
vit[i] = false;
if (ori[i] == num1){
flag = true;
}
}
if (abs(sumB + ori[i] - sumA) <= r){
B.add(ori[i]);
sumB += ori[i];
vit[i] = true;
dfs(key + 1);
B.remove(B.size()-1);
sumB -= ori[i];
vit[i] = false;
}
}
}
}
public static int abs(int a){
return a + (a >> 31) ^ (a >> 31);
}
}