用java解决奶牛分厩问题(含独家详细解析)

题目来源

洛谷P1154 奶牛分厩题目

题目描述

农夫约翰有 N ( 1 ≤ N ≤ 5000 ) N(1 \le N \le 5000) N(1N5000)头奶牛,每头奶牛都有一个唯一的不同于其它奶牛的编号 s i s_i si,所有的奶牛都睡在一个有 K K K个厩的谷仓中,厩的编号为0到 K − 1 K−1 K1。每头奶牛都知道自己该睡在哪一个厩中,因为约翰教会了它们做除法, S i S_i Si m o d mod mod K K K的值就是第 i i i头奶年所睡的厩的编号。
给出一组奶牛的编号,确定最小的 K K K 使得没有2头或2头以上的奶牛睡在同一厩中。

输入格式

第一行一个正整数 N N N,第2到 N + 1 N+1 N+1行每行一个整数表示一头奶牛的编号。

输出格式

一个整数,表示要求的最小的 K K K,对所有的测试数据这样的 K K K是一定存在的。

输入输出样例

输入

5 
4 
6 
9 
10 
13 

输出

8

解题思路

 题目的意思要求我们找出一个最小的K值,使得K模上奶牛所有的编号得到的厩的编号两两不相等。一开始我用暴力for循环的方法,但是只得到80分,显然超时了。所以对于数论问题,一定有公式能方便我们求解。在这道题,我们用到了以下的思想:
 若 a ≡ b ( m o d K ) a \equiv b \pmod K ab(modK),即K模a,b的值相等的条件存在(a,b分别是奶牛的编号),则K能整除|a-b|(由题意知,a,b两两不相等)。
 证明:假设 a = K ∗ n + a 1 a=K*n+a1 a=Kn+a1 b = K ∗ m + b 1 b=K*m+b1 b=Km+b1,其中n,a1,m,b1都为整数,由条件可知,余数a1=b1。所以a-b=K(n-m)。所以,我们要新建一个数组,对编号之间两两相减的值作为索引,并打上标记,再由小到大找那些没有打上标记的索引并输出;
 但是,这样处理完之后,还不是正确。因为我们还没有考虑到|a-b|的因子的情况:若K整除|a-b|,K的因子也能整除|a-b|,但这些因子我们可能没有标记。所以,我们在取得一个未被标记的索引之后,我们还要遍历 K ∗ i K*i Ki,i为大于1的正整数。如果遍历结果都没有标记,那么输出最小值K。

AC代码

import java.util.Scanner;

public class Main {
     
	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		int N = 0;
		Scanner scan = new Scanner(System.in);
		N = scan.nextInt();
		//记录1到N头奶牛的编号
	    int Cow[] = new int[N];
	    int Num[] = new int[1000001];
	    for(int i = 0 ;i < N;i++) {
     
			 Cow[i] = scan.nextInt();
		}
	    for(int i = 0 ;i < N-1;i++) {
     
	    	for(int j = i+1 ;j < N;j++) {
     
		    	Num[Math.abs(Cow[i]-Cow[j])]=1;
		    }
	    }
	    boolean judge = true;
	    //因为厩的数量显然比奶牛的数量多,所以从N开始找;因为余数代表厩的编号肯定小于N,而且厩的编号和奶牛编号一一对应
	    for(int K = N;K < 1000001;K++) {
     
	    	if(Num[K] == 0) {
     
	    		for(int j = K ; j < 1000001;j+=K) {
     
	    			if(Num[K] == 1) {
     
	    				judge = false;
	    				break;
	    			}
	    		}
	    		if(judge) {
     	    			
	    		    System.out.println(K);
	    		    break;
	    		 }
	    	}
	    }
		scan.close();
	}
}

Ps:觉得不错就点个赞吧,期待你的三连!

你可能感兴趣的:(OJ,算法,java,数学)