zoukankan      html  css  js  c++  java
  • 买书

    蒜头君去书店买书,他有 m 元钱,书店里面有 n 本书,每本书的价格为 pi 元。蒜头君很爱学习,想把身上钱都用来买书,并且刚好买 k 本书。请帮蒜头君计算他是否能刚好用 m 元买 k本书。

    输入格式

    第一行输入 33 个整数 m(1m100000000),n(1n30),k(1kmin(8,n))

    接下来一行输入 nn 个整数,表示每本书的价格 pi(1pi100000000)。

    输出格式

    如果蒜头君能 刚好 用 m 元买 k 本书,输入一行"Yes", 否则输出"No"

    样例输入1

    10 4 4
    1 2 3 4

    样例输出1

    Yes

    样例输入2

    10 4 3
    1 2 3 4

    样例输出2

    No

    -------------------------------------------------------------------------------------------------------------------------------------------------------------
    第一种思路:二进制枚举法
    //二进制枚举,会超时,不会错
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Scanner;
    
    public class Main {
    	static int[] book;
    	public static void main(String[] args) {
    		Scanner sc = new Scanner(System.in);
    		int m = sc.nextInt();
    		int n = sc.nextInt();
    		int k = sc.nextInt();
    		int ans = 0;
    		
    		book = new int[n];
    		
    		for(int i = 0; i < n; i ++) {
    			book[i] = sc.nextInt();
    		}
    		
    		for(int i = 0; i < (1 << n); i ++) {
    			int x = 0;
    			List<Integer> list = new ArrayList<Integer>();
    			
    			for(int j = 0; j < n; j ++) {
    				if((i & (1 << j)) != 0) {
    					x ++;
    					list.add(j);
    				}
    			}
    			
    			int sum = 0;
    			Iterator<Integer> iterator = list.iterator();
    			while(iterator.hasNext()) {
    				sum += book[book.length - 1 - iterator.next()];
    			}
    			
    			if(x == k && sum == m)
    				ans ++;
    		}
    		
    		if(ans != 0)
    			System.out.println("Yes");
    		else
    			System.out.println("No");
    	}
    }
    
    第二种思路:随机数骗分法
    //随机数骗分
    public class Main {
        static int[] book;
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int m = sc.nextInt();
            int n = sc.nextInt();
            int k = sc.nextInt();
            
            book = new int[n];
            for(int i = 0; i < n; i ++) {
                book[i] = sc.nextInt();
            }
            
            for(int i = 0; i < 10000000; i ++) {  //数字千万不能设置太大,此处设置1000W即所有都超时
    //            normal版本:不能增加太多次数
                /**
                 * 100次,过了6组
                 * 1000次,过了6组
                 * 1W次,过了7组
                 * 10W次,过了8组
                 * 100W次,过了9组
                 * 可惜1000W次有超时,从OJ数据判断,第10组样例已经通过,得到正确的后break了,但前面No的有超时
                 * ☆☆☆☆☆200W次成功通过!
                 */
                Set<Integer> set = new HashSet<>();
                for(int j = 0; j < k; j ++) {
                    int rand = (int) (Math.random() * n);
                    set.add(rand);    //将随机产生的book数组的序数给放进去
                }
                if(set.size() == k) {
                    Iterator<Integer> iterator = set.iterator();
                    
                    int sum = 0;
                    while(iterator.hasNext())
                        sum += (book[iterator.next()]);
                    
                    if(sum == m) {
                        System.out.println("Yes");
                        System.exit(0);
                    }
                }
    //            理想的better版本:时间和空间占用少,上版Set有多余重复,可以增加次数
                int a = (int) (Math.random() * n);
                int b = (int) (Math.random() * n);
                int c = (int) (Math.random() * n);
                int d = (int) (Math.random() * n);
                
                if(a != b && a != c && a != d && b != c && b != d && c != d) {
                    int sum = book[a] + book[b] + book[c] + book[d];
                    if(sum == m) {
                        System.out.println("Yes");
                        System.exit(0);
                    }
                }
                
                //实际使用中,前者更好???为什么,因为一旦Yes,程序就exit了
            }
            System.out.println("No");
        }
    }
    
    第三种思路:搜索算法
    //超时
    public class Main {
        static int[] book;
        static int[] mark;
        static int n;
        static int m;
        static int k;
        static int ans;
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            m = sc.nextInt();
            n = sc.nextInt();
            k = sc.nextInt();
            ans = 0;
            
            book = new int[n];
            
            for(int i = 0; i < n; i ++) {
                book[i] = sc.nextInt();
            }
            
            mark = new int[n];
            
            dfs(0, 0, 0);
            
            if(ans != 0)
                System.out.println("Yes");
            else
                System.out.println("No");
            
        }
        private static void dfs(int step, int count, int price) {
            if(step == n && count == k && price == m) {
                ans ++;
                return;
            }
            
            if(step == n) {
                return;
            }
            
            for(int i = 0; i < 2; i ++) {  //i = 0不要, i = 1要
                if(mark[step] != 1) {
                    if(i == 0) {
                        mark[step] = 1;
                        dfs(step + 1, count, price);
                        mark[step] = 0;
                    }
                    else {
                        mark[step] = 1;
                        dfs(step + 1, count + 1, price + book[step]);
                        mark[step] = 0;
                    }
                }
            }
        }
    }

    优化:当count > k的时候就可以return, 从而减少递归层数 

    import java.util.Scanner;
    public class Main {
        static int[] book;static int n;
        static int m;
        static int k;
        static int ans;
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            m = sc.nextInt();
            n = sc.nextInt();
            k = sc.nextInt();
            ans = 0;
            
            book = new int[n];
            
            for(int i = 0; i < n; i ++) {
                book[i] = sc.nextInt();
            }
            
            mark = new int[n];
            
            dfs(0, 0, 0);
            
            if(ans != 0)
                System.out.println("Yes");
            else
                System.out.println("No");
            
        }
        
        private static void dfs(int step, int sum, int num) {
            if(step > n || sum > m || num > k) {
                return;
            }
            if(num == k) {
                if(sum == m) {
                    ans ++;
                    return;
                }
                else {
                    return;
                }
            }
            
            if(step == n)
                return;
            
            for(int i = 0; i < 2; i ++) {  //i = 0不要, i = 1要
                if(i == 0) {
                    dfs(step + 1, sum, num);
                }
                else {
                    dfs(step + 1, sum + book[step], num + 1);
                }
            }//循环体可要可不要
        }
    }

     同时, 在这里也是不需要标记的。思考:为什么?

  • 相关阅读:
    mongodb 创建auto increment 自增函数
    QT通过IP地址定位地址(用get方法取数据)
    VC程序快速删除自己(可能做升级程序的时候有用)
    让程序出现在控制面板(写注册表)
    亲测VS2010纯静态编译QT4.8.0,实现VS2010编译调试Qt程序,QtCreator静态发布程序(图文并茂,非常详细) good
    Qt configure 参数不完全说明
    C语言和C++篇
    C#开源实现MJPEG流传输
    前端EASYUI的简化调用
    .NET Mvc Razor
  • 原文地址:https://www.cnblogs.com/jizhidexiaobai/p/8438477.html
Copyright © 2011-2022 走看看