数据结构和算法 数论 中国余数定理

1、中国余数定理概述

        找出所有整数x,它们被3、5、7除时,余数分别为2,3和2。一个这样的解为x = 23,所有的解是形如23 + 105k(k为任意整数)的整数。“中国余数定理”提出,对一组两两互质的模数(如3、5、7)来说,其取模运算的方程组与对其积(如105)取模运算的方程之间存在着一种对应关系。

        中国余数定理被广泛用于计算大整数,因为它允许用几个类似的小整数计算来替换一个知道结果大小界限的计算。

        定理定义如下:给定成对互质正整数n_1, n_2, \cdot \cdot \cdot \cdot \cdot \cdot n_k,和任意整数a_1, a_2, \cdot \cdot \cdot \cdot \cdot \cdot a_k,同时同余系统

        

        有解,且解是唯一的模N = n_1, n_2 \cdots n_k

2、应用示例

输入:num[] = {5, 7}, rem[] = {1, 3}
输出:31
解释:
31 是最小的数,使得:
  (1) 当我们将它除以 5 时,我们得到余数 1。
  (2) 当我们将它除以 7 时,我们得到余数 3。

输入:num[] = {3, 4, 5}, rem[] = {2, 3, 1}
输出:11
解释:
11 是最小的数,使得:
  (1) 当我们将它除以 3 时,我们得到余数 2。
  (2) 当我们将它除以 4 时,我们得到余数 3。
  (3) 当我们将它除以 5 时,我们得到余数 1。

3、应用场景描述

(1)场景1

        2P/Encke彗星、4P/Faye彗星和8P/Tuttle彗星的轨道周期分别为 3 年、8 年和 13 年。这些彗星的最后一次近日点分别发生在 2017 年、2014 年和 2008 年。

        这三颗彗星都将在同一年达到近日点的明年是什么时候?

        对于这个问题,假设时间以整数年为单位,并且每个轨道周期都是常数。

(2)场景2

        一所学校的学生人数在 500 到 600 人之间。如果我们将他们分成 12 人、20 人或 36 人一组,则总是剩下 7 名学生。这所学校有多少学生?

4、代码实现

(1)c++

#include<bits/stdc++.h>
using namespace std;

// k is size of num[] and rem[]. Returns the smallest
// number x such that:
// x % num[0] = rem[0],
// x % num[1] = rem[1],
// ..................
// x % num[k-2] = rem[k-1]
// Assumption: Numbers in num[] are pairwise coprime
// (gcd for every pair is 1)
int findMinX(int num[], int rem[], int k)
{
	int x = 1; // Initialize result

	// As per the Chinese remainder theorem,
	// this loop will always break.
	while (true)
	{
		// Check if remainder of x % num[j] is
		// rem[j] or not (for all j from 0 to k-1)
		int j;
		for (j=0; j<k; j++ )
			if (x%num[j] != rem[j])
			break;

		// If all remainders matched, we found x
		if (j == k)
			return x;

		// Else try next number
		x++;
	}

	return x;
}

int main(void)
{
	int num[] = {3, 4, 5};
	int rem[] = {2, 3, 1};
	int k = sizeof(num)/sizeof(num[0]);
	cout << "x is " << findMinX(num, rem, k);
	return 0;
}

(2)Java

import java.io.*;

class ZGYSDL {
	
	// k is size of num[] and rem[]. Returns the smallest
	// number x such that:
	// x % num[0] = rem[0],
	// x % num[1] = rem[1],
	// ..................
	// x % num[k-2] = rem[k-1]
	// Assumption: Numbers in num[] are pairwise coprime
	// (gcd for every pair is 1)
	static int findMinX(int num[], int rem[], int k)
	{
		int x = 1; // Initialize result
	
		// As per the Chinese remainder theorem,
		// this loop will always break.
		while (true)
		{
			// Check if remainder of x % num[j] is
			// rem[j] or not (for all j from 0 to k-1)
			int j;
			for (j=0; j<k; j++ )
				if (x%num[j] != rem[j])
				break;
	
			// If all remainders matched, we found x
			if (j == k)
				return x;
	
			// Else try next number
			x++;
		}
	
	}
	
	public static void main(String args[])
	{
		int num[] = {3, 4, 5};
		int rem[] = {2, 3, 1};
		int k = num.length;
		System.out.println("x is " + findMinX(num, rem, k));
	}
}

(3)Python


# k is size of num[] and rem[].
# Returns the smallest number x
# such that:
# x % num[0] = rem[0],
# x % num[1] = rem[1],
# ..................
# x % num[k-2] = rem[k-1]
# Assumption: Numbers in num[]
# are pairwise coprime (gcd for
# every pair is 1)
def findMinX(num, rem, k):
	x = 1; # Initialize result

	# As per the Chinise remainder
	# theorem, this loop will
	# always break.
	while(True):
		
		# Check if remainder of
		# x % num[j] is rem[j]
		# or not (for all j from
		# 0 to k-1)
		j = 0;
		while(j < k):
			if (x % num[j] != rem[j]):
				break;
			j += 1;

		# If all remainders
		# matched, we found x
		if (j == k):
			return x;

		# Else try next number
		x += 1;

# Driver Code
num = [3, 4, 5];
rem = [2, 3, 1];
k = len(num);
print("x is", findMinX(num, rem, k));

(4)c#

using System;

class ZGYSDL
{
	
	// k is size of num[] and rem[].
	// Returns the smallest
	// number x such that:
	// x % num[0] = rem[0],
	// x % num[1] = rem[1],
	// ..................
	// x % num[k-2] = rem[k-1]
	// Assumption: Numbers in num[]
	// are pairwise coprime
	// (gcd for every pair is 1)
	static int findMinX(int []num, int []rem,
						int k)
	{
		
		// Initialize result
		int x = 1;
	
		// As per the Chinese remainder theorem,
		// this loop will always break.
		while (true)
		{
			// Check if remainder of x % num[j] is
			// rem[j] or not (for all j from 0 to k-1)
			int j;
			for (j = 0; j < k; j++ )
				if (x % num[j] != rem[j])
				break;
	
			// If all remainders matched, we found x
			if (j == k)
				return x;
	
			// Else try next number
			x++;
		}
	
	}
	
	public static void Main()
	{
		int []num = {3, 4, 5};
		int []rem = {2, 3, 1};
		int k = num.Length;
		Console.WriteLine("x is " + findMinX(num,
										rem, k));
	}
}

(5)php

<?php

// k is size of num[] and rem[].
// Returns the smallest number x
// such that:
// x % num[0] = rem[0],
// x % num[1] = rem[1],
// ..................
// x % num[k-2] = rem[k-1]
// Assumption: Numbers in num[]
// are pairwise coprime (gcd for
// every pair is 1)
function findMinX($num, $rem, $k)
{
	$x = 1; // Initialize result

	// As per the Chinise remainder
	// theorem, this loop will
	// always break.
	while (true)
	{
		// Check if remainder of
		// x % num[j] is rem[j]
		// or not (for all j from
		// 0 to k-1)
		$j;
		for ($j = 0; $j < $k; $j++ )
			if ($x % $num[$j] != $rem[$j])
			break;

		// If all remainders
		// matched, we found x
		if ($j == $k)
			return $x;

		// Else try next number
		$x++;
	}

	return $x;
}

// Driver Code
$num = array(3, 4, 5);
$rem = array(2, 3, 1);
$k = sizeof($num);
echo "x is " ,
	findMinX($num, $rem, $k);

?>

(6)javascript

<script>
	
// k is size of num and rem. Returns the smallest
// number x such that:
// x % num[0] = rem[0],
// x % num[1] = rem[1],
// ..................
// x % num[k-2] = rem[k-1]
// Assumption: Numbers in num are pairwise coprime
// (gcd for every pair is 1)
function findMinX(num , rem , k)
{
	var x = 1; // Initialize result

	// As per the Chinese remainder theorem,
	// this loop will always break.
	while (true)
	{
		// Check if remainder of x % num[j] is
		// rem[j] or not (for all j from 0 to k-1)
		var j;
		for (j=0; j<k; j++ )
			if (x%num[j] != rem[j])
			break;

		// If all remainders matched, we found x
		if (j == k)
			return x;

		// Else try next number
		x++;
	}

}

// Driver method
var num = [3, 4, 5];
var rem = [2, 3, 1];
var k = num.length;
document.write("x is " + findMinX(num, rem, k));
</script>

猜你喜欢

转载自blog.csdn.net/bashendixie5/article/details/124974861