编程之美——读书心得 2.8找符合条件的整数
2014-03-18 14:42
281 查看
问题:任意给定一个正整数,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0。
看了题目要求之后,我们的第一想法就是从小到大枚举M的取值,然后再计算N * M,最后判断它们的乘积是否只含有1和0。大体的思路可以用下面的伪代码来实现:
for(M = 2; ; M++)
{
product = N * M;
if(HasOnlyOneAndZero(product))
output N, M, Product, and return;
}
但是问题很快就出现了,什么时候应该终止循环呢?这个循环会终止吗?即使能够终止,也许这个循环仍需要耗费太多的时间,比如N = 99时,M = 1 122 334 455 667 789,N * M = 111 111 111 111 111 111。
分析从这里开始:
我们要求得M,首先要证明M存在。
一、证明:M一定存在,而且不唯一。
100%N,101%N,102%N,...,10x%N....这是一个无穷数列,且数列中每一项取值范围都在[0,N-1]之。所以这个无穷数中间必定才能在循环节假设 s,t 均为正整数,且s<t ,
10s%N = 10t%N 则 10t-s%N = 1 , t-s是N的循环节
(之前在哪看到的,我忘记了,不好意思。这里不是很懂)
二、求解M。
问题转换,由最初的暴力求解M使得N*M的乘积有1和0转换为===>求解最小的正整数X,使得X的十进制表示只有1和0,并且X被N整除。
X的取值:1,,1,11,100,101,110,111,1000,……
若X最终位为K位,则要循环搜索2^k次,所以寻找最小的X,使得X mod N ==0即可。
我插入一些关于取模定律的知识:
同余式:a,b对p取模,它们余数相同,记做 a ≡ b (mod p)
定律:若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p);
若a≡b (% p),则对于任意的c,都有(a * c) ≡ (b * c) (%p);
应用到这里,
∵1%3=1, 10%3=1;
∴1≡10%3
所以,(1+100)%3≡(10+100)%3,即101%3≡110%3
所以,可以只计算同位数小的数值即可。x,10x,10x+1 同余
例如,1001与1010
设 X=10^k, 10^k %N =a
那么X为K+1 位时, X = 10^k +Y (0<Y<10^k)
对Y搜索,将有2^k-1个数据。
那么可以这样处理(思想):把Y按照对N的余数分解,将搜索空间分成N-1个子空间。对于每一个子空间,只需判断其中最小元素加上10^k能否被N整除即可。
这样,搜索空间从2^k-1压缩至N-1维。(前提是前面的计算已保留了余数信息,并且把Y的搜索空间进行了分解,即X%N的各种可能)
然后,10^k与Y的取模结果想加,再%N,看是否有新余数产生。这一步需要循环N次,因为已经将Y分成了N租。那么总的部署为(K-1)*N步。(从根至叶子自顶向下,深度搜索余数信息的次数)
参考信息:http://blog.csdn.net/jcwKyl/article/details/3859155
看了题目要求之后,我们的第一想法就是从小到大枚举M的取值,然后再计算N * M,最后判断它们的乘积是否只含有1和0。大体的思路可以用下面的伪代码来实现:
for(M = 2; ; M++)
{
product = N * M;
if(HasOnlyOneAndZero(product))
output N, M, Product, and return;
}
但是问题很快就出现了,什么时候应该终止循环呢?这个循环会终止吗?即使能够终止,也许这个循环仍需要耗费太多的时间,比如N = 99时,M = 1 122 334 455 667 789,N * M = 111 111 111 111 111 111。
分析从这里开始:
我们要求得M,首先要证明M存在。
一、证明:M一定存在,而且不唯一。
100%N,101%N,102%N,...,10x%N....这是一个无穷数列,且数列中每一项取值范围都在[0,N-1]之。所以这个无穷数中间必定才能在循环节假设 s,t 均为正整数,且s<t ,
10s%N = 10t%N 则 10t-s%N = 1 , t-s是N的循环节
(之前在哪看到的,我忘记了,不好意思。这里不是很懂)
二、求解M。
问题转换,由最初的暴力求解M使得N*M的乘积有1和0转换为===>求解最小的正整数X,使得X的十进制表示只有1和0,并且X被N整除。
X的取值:1,,1,11,100,101,110,111,1000,……
若X最终位为K位,则要循环搜索2^k次,所以寻找最小的X,使得X mod N ==0即可。
我插入一些关于取模定律的知识:
同余式:a,b对p取模,它们余数相同,记做 a ≡ b (mod p)
定律:若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p);
若a≡b (% p),则对于任意的c,都有(a * c) ≡ (b * c) (%p);
应用到这里,
∵1%3=1, 10%3=1;
∴1≡10%3
所以,(1+100)%3≡(10+100)%3,即101%3≡110%3
所以,可以只计算同位数小的数值即可。x,10x,10x+1 同余
例如,1001与1010
设 X=10^k, 10^k %N =a
那么X为K+1 位时, X = 10^k +Y (0<Y<10^k)
对Y搜索,将有2^k-1个数据。
那么可以这样处理(思想):把Y按照对N的余数分解,将搜索空间分成N-1个子空间。对于每一个子空间,只需判断其中最小元素加上10^k能否被N整除即可。
这样,搜索空间从2^k-1压缩至N-1维。(前提是前面的计算已保留了余数信息,并且把Y的搜索空间进行了分解,即X%N的各种可能)
然后,10^k与Y的取模结果想加,再%N,看是否有新余数产生。这一步需要循环N次,因为已经将Y分成了N租。那么总的部署为(K-1)*N步。(从根至叶子自顶向下,深度搜索余数信息的次数)
// 将搜索空间分过类的广度搜索,这样空间占用是O(N)而不是 // 指数级。分类的原则是按照模N的余数分类 #define _CRT_SECURE_NO_WARNINGS 1 #include <cstdio> #include <bitset> #include <vector> #include <queue> using namespace std; struct QNode { int v, r; // v is value, r is remainder QNode(int vv, int rr): v(vv), r(rr) {} QNode(): v(0), r(0) {} }; int main() { int N; while(scanf("%d", &N) != EOF) { //bitset<N> bn; queue<QNode> q; q.push(QNode(1, 1)); while(!q.empty()) { //bn.reset(); vector<bool> bn(N, false); int s = q.size(); while(s--) { QNode t = q.front(); if(t.r == 0) { printf("n = %d, m = %d, n*m = %d/n", N, t.v/N, t.v); goto ok; } q.pop(); if(!bn[t.r * 10 % N]) { //注意这里 bn[t.r * 10 % N] = true; q.push(QNode(t.v * 10, t.r * 10 % N)); } if(!bn[(t.r * 10 + 1) % N]) { bn[(t.r * 10 + 1) % N] = true; q.push(QNode(t.v * 10 + 1, (t.r * 10 + 1) % N)); } } } ok:; } return 0; }
参考信息:http://blog.csdn.net/jcwKyl/article/details/3859155
相关文章推荐
- 编程之美2.8 找符合条件的整数
- 编程之美:第二章 数字之魅 2.8找到符合条件的整数
- 【编程之美2.8】找符合条件的整数
- 编程之美2.8 找符合条件的整数
- 编程之美2.8 找符合条件的整数
- 编程之美2.8——找符合条件的整数
- 编程之美——2.8 找符合条件的整数
- 编程之美2.8 找符合条件的整数 求十进制表示只含1和0的正整数
- 编程之美2.8找符合条件的整数
- 编程之美2.8 | 找符合条件的整数
- 编程之美——找符合条件的整数
- 编程之美——找符合条件的整数
- 编程之美 2.8 找符合条件的正数
- 编程之美--找个符合条件的整数
- 读书笔记之编程之美 – 2.8 找符合条件的整数
- 《编程之美》读书笔记(十三):“找符合条件的整数”
- 连载5:寻找符合条件的整数(《编程之美》第2.8节)
- [编程之美] PSet2.8 找符合条件的整数
- 《编程之美》找符合条件的整数之C语言实现
- 【编程之美】2.8 找符合条件的整数