资源限制
时间限制:1.0s 内存限制:256.0MB
【问题描述】
给一个正整数n,输出它所有的正整数加法的分解方法。
注意:
1. 根据输入的要求决定交换加数的位置是否视为不同的分解方案。
2. 不分解也视为一种分解方案。
3. 按字典序输出所有分解方案,格式见样例。
【输入格式】
输入共1行,包含2个正整数n和m,之间用一个空格隔开。n表示待分解正整数,m是1或者2:
1表示交换加数的位置是否视为不同的分解方案;
2表示交换加数的位置是否视为相同的分解方案。
【输出格式】
输出若干行,每行表示一种分解方案。对于一种方案,先输出n,再输出一个“=”。然后输出分解的各数,不同的数之间用一个“+”连接。
样例输入
5 2
样例输出
5=1+1+1+1+1
5=1+1+1+2
5=1+1+3
5=1+2+2
5=1+4
5=2+3
5=5
【输入输出样例2】
样例输入
5 1
样例输出
5=1+1+1+1+1
5=1+1+1+2
5=1+1+2+1
5=1+1+3
5=1+2+1+1
5=1+2+2
5=1+3+1
5=1+4
5=2+1+1+1
5=2+1+2
5=2+2+1
5=2+3
5=3+1+1
5=3+2
5=4+1
5=5
数据规模和约定
对于50%的数据有M=1,另有50%的数据有M=2。对100%的数据,n≤15。
解题思路:
将某数分解为较小数的和,相当于“伪全排列”,即对元素的个数和使用次数都不做要求。只要搜索时不传入“step”参数,并将返回值得处理稍作修改。当要求分解项可以重复时,直接将搜索出的值拼接输出即可。当要求不能重复时,还需要对集合和集合作去重处理,将大集合存放排好序的小集合,接着双重for处理,最后将符合条件的集合拼接并输出。
java代码:
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] split = br.readLine().split(" ");
int n = Integer.parseInt(split[0]);
int flag = Integer.parseInt(split[1]);
Temp645 obj = new Temp645(n, flag);
obj.dfs();
System.out.println(obj.builder);
}
}
class Temp645{
int n;//待分解数
int flag;//分解类型
int sum = 0;//单前总和
List<Integer> list = new ArrayList<>();//存储实时分解项
StringBuilder builder = new StringBuilder();//存储最终答案
List<List<Integer>> listAll = new ArrayList<>();//存储类型2的不重复集合项
public Temp645(int n, int flag) {
this.n = n;
this.flag = flag;
}
public void dfs() {//由于分解个数无要求,不传“step”参数
if(sum >= n) {//当前和大于n时,直接返回,等于时作进一步处理
if(sum == n) {
if(flag == 1) {
print1();
}else {
print2();
}
return;
}else {
return;
}
}
for(int i = 1; i <= n; i++) {
if(sum < n) {//当前和比目标和小时才累加,大于时,不处理
sum += i;
list.add(i);//存放实时分解项
dfs();
sum -= i;//回溯
list.remove(list.size() - 1);
}
}
}
private void print1() {//将此时list中的分解项作格式化处理,并拼接至builder
builder.append(n + "=");
for(int i = 0; i < list.size() - 1; i++) {
builder.append(list.get(i) + "+");
}
builder.append(list.get(list.size() - 1) + "\n");//最后一项无加号
}
private void print2() {//主要实现对储存集合的集合的去重处理
int []arr = new int[list.size()];//将原list中值拷贝到arr中
for(int i = 0; i < list.size(); i++) {
arr[i] = list.get(i);
}
Arrays.sort(arr);//排序
for(int i = 0; i < listAll.size(); i++) {//遍历存放集合的集合
List<Integer> temp = listAll.get(i);
int j = 0;
for(j = 0; j < temp.size(); j++) {
if(temp.get(j) != arr[j]) {//当有一项不同时,则证明此时的两集合不同,进行下一集合比较
break;
}
}
if(j == temp.size()) {//表示当前两集合元素完全相同
return;//直接返回,不添加到去重集合和builder
}
}
List<Integer> list2 = new ArrayList<>();//将排好序的arr转化至集合
for(int i = 0; i < arr.length; i++) {
list2.add(arr[i]);
}
listAll.add(list2);//添加至去重集合
print1();//将此集合拼接至builder
}
}