• Java 蓝桥杯 算法训练(VIP) 最大体积


    最大体积

    问题描述
      每个物品有一定的体积(废话),不同的物品组合,装入背包会战用一定的总体积。
    假如每个物品有无限件可用,那么有些体积是永远也装不出来的。
    为了尽量装满背包,附中的OIER想要研究一下物品不能装出的最大体积。
    题目保证有解,如果是有限解,保证不超过2,000,000,000
      如果是无限解,则输出0
    输入格式
      第一行一个整数n(n<=10),表示物品的件数
      第2行到N+1行: 每件物品的体积(1<= <=500)
    输出格式
      一个整数ans,表示不能用这些物品得到的最大体积。
    样例输入
    3
    3
    6
    10
    样例输出


    题解:
    小编这里弄好了两份代码,在网上也是参考了很多大佬的代码,这道题可能算是一个小型的动态规划吧

    第一个:这个相对来说好理解一些,最主要的就是在两层for循环那里,把每一个可能加的数都加上了,小编直接用下标代表数了,然后打上记号,最后倒着输出那个没有被标记过的下标
    (其实dp[j]一直在变,每次能加上的时候就把下标变成1,如果没有被用过就为初始的0,)

    import java.util.Scanner;
    
    public class Main {
    	public static int n;
    	public static int temp;
    	public static int [] a = new int [11];
    	public static int [] dp = new int [100000];
    	public static int gcd(int a,int b) {
    		 if (a % b == 0)
    		        return b;
    		    else
    		        return gcd(b, a % b);
    	}
    	public static int gcdAll(){
    		   temp = a[0];
    		    for (int i = 1; i < n; i++)
    		    {
    		        temp = gcd(temp, a[i]);
    		    }
    		    return temp;
    	}
    	public static void main(String[] args) {
    		  Scanner sc = new Scanner(System.in);
    		   n = sc.nextInt();
    		    for (int i = 0; i < n; i++)
    		        a[i]=sc.nextInt();
    
    		    if (gcdAll() == 1)    //如果所有数的最大公约数为1,则有解,否则为无限解 
    		    {
    		        dp[0] = 1;
    		        for (int i = 0; i < n; i++)
    		        {
    		            for (int j =a[i]; j <= 100000-1; j++)
    		            {
    		                if (dp[j - a[i]] == 1)    //i=0时,j为goods[0]的倍数;
    		                                                  //接下来,j为 goods[i]中物品体积值组合的结果 
    		                    dp[j] = 1;
    		            }
    		        }
    		        
    		        for (int i = 100000-1; i >= 0; i--)        //逆序遍历所有的体积结果,将第一个不能组合的数输出后结束 
    		        {
    		            if (dp[i]==0)
    		            {
    		               System.out.println(i);
    		               break;
    		            }
    		        }
    		    }
    		    else {
    		    	System.out.println("NONE");
    		    }
    
    	}
    	
    }
    
    

    第二个:这一个用了一个数学知识 -------代数几何里面的–贝祖等式
    相比第二个就要比第一个占用的内存少很多先放代码吧,证明写在下面

    import java.util.Scanner;
    
    public class Main{
    	public static int n;
    	public static int[] A = new int[11];
    	public static int[] flag = new int[250010];
    
    	public static void main(String[] args) {
    		int ans = 0, z, i, j, max = -100;
    		Scanner sc = new Scanner(System.in);
    		n = sc.nextInt();
    		for (int z1 = 0; z1 < n; z1++) {
    			A[z1] = sc.nextInt();
    		}
    		max = -100;
    		for (i = 0; i < n; i++)
    			for (j = i + 1; j < n; j++)
    				if (Gcd(A[i], A[j]) == 1) {
    					max = A[i] * A[j] - A[i] - A[j];
    					break;
    				}
    
    		if (max == -100)
    			ans = 0;
    		else
    			for (i = 1; i <= max; i++)
    				for (z = 0; z < n; z++)
    					if (i - A[z] >= 0)
    						if (flag[i - A[z]] == 1) {
    							flag[i] = 1;
    							break;
    						} else
    							ans = i;
    
    		System.out.println(ans);
    
    	}
    
    	private static int Gcd(int a, int b) {
    
    		if (b == 0)
    			return a;
    		return Gcd(b, a % b);
    	}
    
    }
    
    

    这里相对于第一个代码优化的就是,两个相互质数的直接取出来,然后不是相互质数的在去进行循环

    相对于这道题来说:求两个质数的最大取不到的数目(也就是两个质数无论如何也不能拼凑到的数中最大的那个)

    假设有 a 和 b 两个质数,求他俩取不到的数目简单的式子就是

    a*b-a-b

    如果有兴趣的话,可以继续研究一下,(但这个应该不是找程序员的大佬了,应该去找数学大佬)下面是一个大概的证明方法

    (这里有个小推荐,你可以搜索一下 蓝桥杯–买不到的数,这道题完全就是这个式子,因为 OJ 给出的测试用例全是质数,导致一个三行的代码就可以解答那道题,搜索这道题应该就可以更详细的来解释这个式子了)

    当然如果研究不懂得话,那就直接记下这个式子吧
    就当1+1=2记下吧,没有为什么

    证明:

    • a或者b是1的情况下容易证明. 以下情况都是a>1且b>1的情况. 首先证明ab-a-b不能表示成ax+by
      假设ab-a-b=ax+by,那么ab=am+bn (m,n都大于等于1) 左边是a的倍数,右边am是a的倍数,那么要求bn也要是a的倍数
      b不是a的倍数,只能要求n是a的倍数,这样的话,bn=bn’a>=ba 那么am=ab-bn所以am1矛盾.
      接着证明ab-a-b+i能表示成ax+by(i>0) 因为ab互质,最大公约数就是1,根据辗转相减的方法知ma+nb=1,
      不妨假设m>0,n1(m=0意味着nb=1不可能的),所以ab-a-b+i(ma+nb)=(im-1)a+(a+in-1)b
      im-1>0,现在只要证明a+in-1>=0,因为ima+inb=i
      如果,|in|>ja其中j>0,那么ima=i+|in|b>jab,所以im>jb
      所以ima+inb=(im-jb)a-(|in|-ja)b=i,说明|in|>ja时,我们就能调整im,in使得|in|

      1、我假装大家都知道贝祖等式:ax+by = gcd(a,b)。证明略。我们可以求出这个特解,然后求出ax+by = c的通解。

      2、这里,题目要求的是有负整数解时(x,y中有负数)c最大是多少。

      3、ax+by = c要有解时,则当 gcd(a,b)|c (c%gcd(a,b) == 0)时,该方程才有解。明显,当gcd(a,b)
      不为1时,方程无解的情况是无穷多个的,因此不存在最大不能组合的数。

      4、我们总能求出x和y的一个特解,即把贝祖等式求解后的x和y,但是x和y的解可以是负数解。

      5、显然这里x和y不能为负数,因此,该题目的问题得以有解答。求最大不能组合的数。

      6、这里又有一条定理:当gcd(a,b) == 1 时(a和b互质),当c>ab-a-b时,方程ax+by =
      c有非负解。所以最大不能组合出的数目就是 a
      b-a-b
      。这里假设大家都知道这条定理,当然不知道也没关系,至少现在你知道了,可以自己试着证明一下,参考上面证明过程。

  • 相关阅读:
    datanode报错Problem connecting to server
    使用命令查看hdfs的状态
    Access denied for user root. Superuser privilege is requ
    ElasticSearch默认的分页参数 size
    SparkStreaming Kafka 维护offset
    【容错篇】Spark Streaming的还原药水——Checkpoint
    251 Android 线性与相对布局简介
    250 Android Studio使用指南 总结
    249 如何解决项目导入产生的中文乱码问题
    248 gradle更新问题
  • 原文地址:https://www.cnblogs.com/a1439775520/p/13079280.html
Copyright © 2020-2023  润新知