首页 > 试题广场 >

求和

[编程题]求和
  • 热度指数:21129 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
输入两个整数 n 和 m,从数列1,2,3.......n 中随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来

输入描述:
每个测试输入包含2个整数,n和m


输出描述:
按每个组合的字典序排列输出,每行输出一种组合
示例1

输入

5 5

输出

1 4<br/>2 3<br/>5
import java.util.*;
public class Main{
    public static void dfs(int i, int n, int m, ArrayList<Integer> list){
        if(m == 0){
            for(int j = 0; j < list.size(); j++){
                if(j != list.size()-1){
                    System.out.print(list.get(j) + " ");
                }
                else{
                    System.out.println(list.get(j));
                }
            }
        }
        else{
            for(int j = i+1; j <= n; j++){
                list.add(j);
                dfs(j, n, m-j, list);
                list.remove(list.size()-1);
            }
        }
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        ArrayList<Integer> list = new ArrayList<>();
        for(int i = 1; i <= n; i++){
            list.add(i);
            dfs(i, n, m-i, list);
            list.remove(list.size()-1);
        }
    }
}

编辑于 2021-08-02 10:59:29 回复(0)
/*思路:实质就是暴力解决问题,将所有的情况枚举出来,然后删选出符合自己要求的结果

   对于1,2,3....n的数中随便选出其中几个出来,只要和是m,就以字典序输出
   其实就是取决于我对于每个数的取舍问题:
     比如  对于数字 1 我只有两种策略:要或者不要   
                                        要的我用res记录下来,并且加到sum中
                                        不要的我直接过(可参照下面代码)
           对于数字 2 我也只有两种策略:要或者不要  
   依次类推..........

   最后的结束标志:就是我到最后一个数字 n 判定完成之后,看我的 sum 和 m 是否相等
                   相等就输出,然后结束这一个分支的递归
                   不相等就不输出,但是也要结束这个分支的递归   

   按照先要再不要的策略,最后输出的结果就是字典序。
*/

import java.util.*;
public class Main{
    public static void main(String [] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        String res = "";//用来记录被选到的数
        int sum = 0; //用来记录被选到数加起来的总和
        int []num = new int[n];
        int j =1;
        for(int i = 0;i < n;i++)
              num[i] = j++; 
        process(num,m,res,sum,0);
    }
    
    public static void process(int[] num,int m,String res,int sum,int i){
        if(i == num.length){
            if(sum == m)
                               //这里用trim()方法就是去除每个输出最后的一个空格
                System.out.println(res.trim());
            return;
        }
               //表示我将num[i]这个数选到了
        process(num,m,res+num[i]+" ",sum+num[i],i+1);
                
               //表示我不要num[i]这个数
        process(num,m,res,sum,i+1);
    }
}

发表于 2019-03-04 16:52:29 回复(0)
虽然通过了编译,但是这是错的。
因为我考虑了一个数的和,两个数的和,三个数的和,分别为m时的遍历。
但是如果某种情况下,4个数的和为m,就无能为力了。
请问谁可以告诉我一下解题思路?谢谢!


import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();

        int[] array;
        array=new int[n];
        for(int i=0;i<n;i++){
            array[i]=i+1;
        }
        
        for(int i=0;i<n;i++){
            if (array[i]==m){
                System.out.println(array[i]);
            }// 一个数的和为m
            for(int j=i+1;j<n;j++){{
                if (array[i]+array[j]==m){
                    System.out.println(array[i]+" "+array[j]);
                }
            }//两个数的和为m
                for(int z=j+1;z<n;z++){
                if (array[i]+array[j]+array[z]==m){
                    System.out.println(array[i]+" "+array[j]+" "+array[z]);
                }
            }//三个数的和为m;
            }
        }
    }
}
发表于 2018-10-11 04:51:50 回复(0)
public class Main {
    
    static int n;
    static int m;
    public static void main(String[] args) {
        
        Scanner scan=new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        int[][] sum=new int[n+1][m+1];
        sum[0][0]=1;
        for (int i = 1; i < n+1; i++) {
            sum[i][0]=1;
            for (int j = 0; j < m+1; j++) {
                if (j<i) {
                    sum[i][j]=sum[i-1][j];
                }
                else {
                    sum[i][j]=sum[i-1][j]+sum[i-1][j-i];
                }
            }
        }
        ArrayList<Integer> list=new ArrayList<>();
        get(1,0,0,list);

        System.out.println(sb.toString());

    }
    
    static StringBuffer sb=new StringBuffer();
    private static void get(int i, int j, int sum, ArrayList<Integer> list) {
        
        for (int k = i; k <= n; k++) {
            
            int    p=sum+k;            
            list.add(k);
            if (p==m) {
                write(list);
                list.remove(new Integer(k));
                break;
            }
            if (k+1<=n) {                                    
                get(k+1, j, p,list);
            }
            if (p>m) {
                list.remove(new Integer(k));
                break;
            }
            list.remove(new Integer(k));
            
        }        
    }
    private static void write(ArrayList<Integer> list) {
        if (sb.length()>0) {
            sb.append("\n");
        }
        for (int i = 0; i < list.size()-1; i++) {
            sb.append(list.get(i)+" ");
        }
        sb.append(list.get(list.size()-1));
    }
}
发表于 2018-10-02 11:31:33 回复(0)
从1到n,每个数都有可能选或者不选,ArrayList<Integer> list 记录已经选的数,用于打印输出,m是题目要的和,sum是当前累加的和,now就是已经从1走到几了,max是n,或者m,就是说now大于这个数后sum就不必再加now了,比max大的数肯定已经比m大了,若sum>m或者now>max+1;说明上一步list.add(now);是没用的,需要去掉 list.remove(new Integer(now));代码如下

import java.util.ArrayList;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            int n = in.nextInt();
            int m = in.nextInt();
            getCount(1,n<m?n:m,m,0,new ArrayList<Integer>(),false);
        }
    }
    public static void getCount(int now,int max,int m, int sum,ArrayList<Integer> list,boolean isadd){
        if(now > max+1 || sum>m){
            if(isadd)
                list.remove(new Integer(now-1));
            return;
        }
        else if(m==sum){
            for(int i=0;i<list.size()-1;i++)
                System.out.print(list.get(i)+" ");
            System.out.println(list.get(list.size()-1));
        }
        else{
            list.add(now);
            getCount(now+1,max,m,sum+now,list,true);
            list.remove(new Integer(now));
            getCount(now+1,max,m,sum,list,false);
        }
    }
}

编辑于 2018-08-28 22:45:27 回复(0)
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;
/**
 分析:     
 1、一个数时表示:
 只有 n>m 时 才会有 n内的一个数等于m,可以最后判断考虑
 2、两个数时:
  m=1+(m-1)=2+(m-2)=i+(m-i)控制(i<m-i),如果(m-i<n)那么这一组数字满足要求,添加进入list,
 3、三个数时:
  三个数就是把两个数中较大的数拆分,要增加数字数量,不会出现 m = n 的情况 ,而为了避免重复,较小的数也必须从i+1开始
  那么就是  (i+1)--(m-i-1)范围内查找,用i+1替代i 用m-i-1替代m 循环控制(i< m-i)寻找满足要求的数。  
   ......
  解题:
   1、递归查找
   2、解决一个数问题
   3、排序
   4、输出
 */
public class Main {
static public LinkedList res = new LinkedList(); 
static public void f(    int p/*记录小数字避免重复*/,
                         int n,
                         int m,
                         String rstr/*已经选出的小数字*/) {
    // 每次从 p等于上层的i+1开始循环
    for (int i = p; i <m-i; i++) {
        if (m-i<=n/*两个数中较大的数小于n说明都在范围内*/) {
            //符合范围 保存: 上一层较小的数+拆分后的小数+拆分后的大数
            String s=(rstr+" "+i+" "+(m-i)).trim();
            res.add(s);
        }
        /*  递归  */
        f(i+1, n,m-i/* m */, rstr+" "+i/*将小数保存,拆分大数*/);
    }
}
public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int m = sc.nextInt();
    // 递归查找
    f(1, n, m,"");
    // 处理 m=n
    if (m<=n) res.add(m+""); // 最后处理 m==n 时的一
    res.sort(null);            // 排序
    for (String string : res) {
        System.out.println(string);
    }
}
}

编辑于 2018-04-22 16:05:18 回复(0)
一种变相的组合问题
把"求n个数字组成相加和为m"的问题分解为两个子问题:
1.组合里面包含第一个数字x,那么下一步求剩余的n-1个数字和为m-x的问题
2.组合里面不包含第一个数字x,那么下一步求剩余的n-1个数字中和为m的问题
这两个子问题都可以用递归的方式解决
import java.util.*;
public class Main{
    static List<Integer> list = new ArrayList<>();
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n,m;
        while(in.hasNext()){
            n = in.nextInt();
            m = in.nextInt();
            Combination(1,n,m,list);  //从数字1开始,最大到n,累加和为m
        }
    }
    private static void Combination(int begin,int n,int m,List<Integer> list){
        if(m == 0){
            for(int j = 0;j<list.size()-1;j++)
                System.out.print(list.get(j)+" ");
            System.out.println(list.get(list.size()-1));
            return;
        }
        if(begin > n || m < 0){
            return;
        }
        list.add(begin);
        Combination(begin+1,n,m-begin,list);
        list.remove(list.size()-1);
        Combination(begin+1,n,m,list);
    }
}

发表于 2018-03-17 13:15:54 回复(0)
使用回溯法
import java.util.*;

public class Main {

	static ArrayList<List<Integer>> res = new ArrayList<>();

	public static void main(String[] args) {
		
		Scanner cin = new Scanner(System.in);

		int N = cin.nextInt();
		int M = cin.nextInt();
		List<Integer> list = new ArrayList<>();
		//当n>m时,其实大于部分是不可能取到的
		int min = N < M ? N : M;

		printList(min, M, 0, 1, list);
                //按照字典序排列
		Collections.reverse(res);
		for (int i = 0; i < res.size(); i++)
			print(res.get(i));

	}

	private static void printList(int N, int M, int m, int n, List<Integer> list) {

		if (m == M) {
			ArrayList<Integer> result = new ArrayList<Integer>();
			result.addAll(list);
			res.add(result);
			return;
		}

		if (n > N || m > M) {
			return;
		}
                //不放入
		printList(N, M, m, n + 1, list);
                //放入
		list.add(Integer.valueOf(n));
		printList(N, M, m + n, n + 1, list);
                //回溯
		list.remove(Integer.valueOf(n));
	}

	private static void print(List<Integer> list) {

		for (int i = 0; i < list.size(); i++) {
			if (i != 0)
				System.out.print(" ");
			System.out.print(list.get(i));
		}
		System.out.println();
	}

}

发表于 2017-09-07 14:29:05 回复(0)
import java.util.ArrayList;
import java.util.Scanner;

public class Main{
	static ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
	static ArrayList<Integer> list = new ArrayList<>();
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		int n, m;
		
		while(sc.hasNext()) {
			n = sc.nextInt();
			m = sc.nextInt();
			dfs(1, m, n);
			for(ArrayList<Integer> l : res) {
				int i = 0;
				for(; i < l.size() - 1; i++) {
					System.out.print(l.get(i) + " ");
				}
				System.out.println(l.get(i));
			}
		}
	}
	
	public static void dfs(int index, int count, int n) {
		if(count == 0) {
			res.add(new ArrayList<>(list));
		}
		else {
			for(int i = index; i <= count && i <= n; i++) {
				list.add(i);
				dfs(i + 1, count - i, n);
				list.remove(list.size() - 1);
			}
		}
	}
}

编辑于 2017-07-24 10:54:55 回复(8)
//大概思想使用回溯法,左子树进行进栈操作,右子树进行出栈操作,采用深度遍历的方法进行遍历,主要的模板是
1.所有的条件判断,如果是则触发return;
2.否则进行左子树入栈操作,右子树出栈操作
import java.util.ArrayList; import java.util.List; import java.util.Scanner; /**  * Created by Yuan on 2017/3/1.  */ public class Main { private static List<Integer> result=new ArrayList<Integer>(); public static void main(String[] args){
        Scanner scanner=new Scanner(System.in); int n= scanner.nextInt(); int m=scanner.nextInt(); int minMN=m>n?n:m; //get max length of the data  int currentPos=0; int currentSum=0; int[] number=new int[minMN]; for (int i=0;i<minMN;i++){
            number[i]=i+1;
        } DFS(currentPos, minMN, m, currentSum,number);

    } public static void DFS(int currentPos,int n,int m,int currentSum,int[] number){ //判断当前指针是否到达最大数,若到达则结束算法,否则继续    if (currentSum>m){ return;
        } if (currentSum==m){ //print  int len=result.size(); for (int i=0;i<len-1;i++){
                System.out.print(result.get(i)+" ");
            }
            System.out.println(result.get(len - 1)); return;
        } if (currentPos>=n){ return;
        } //左子树进站,进站后需要计算当前的和   currentSum=number[currentPos]+currentSum; result.add(number[currentPos]); DFS(currentPos+1,n,m,currentSum,number); //右边子树出站,出站,只为了促进左子树的查找,右子树的和不会成为这个情况的  //出站  result.remove(result.size()-1); DFS(currentPos + 1, n, m, currentSum-number[currentPos],number);


    }
}

发表于 2017-03-02 15:08:45 回复(3)