您的位置:首页 > 编程语言

编程之美-找符合条件的整数

2012-03-29 19:57 316 查看
题目:

任意给定一个正整数N,求一个最小的正整数M(M>1),使得N * M的十进制表示形式里只含有1和0。

看了题目,我很自然的想到了枚举。然后看N * M的十进制是否只包含1和0。当然,这种暴力的解法不是我们想要的。

换一种枚举方法,我们枚举N*M的取值效果怎么样呢?因为N * M的只包含1和0,所以对于K位的N*M,需要搜索2的K次方。

因为找的是最小整数,所以可以采用BFS(宽度优先搜索)。如果最终解使得N * M有k位,那么总共要搜索2的(k+1)次方。有什么方法可以剪枝么?

答案是肯定的。

当N = 3时,看如下搜索树,括号内容表示mod N的值:



令X = 101 Y=110,可知X与Y同余。

所以10X + 0与10Y + 0同余,10X + 1与10Y + 1同余,并且易知,从X继续往下搜索的值,一定比Y的小。要求最小的M,我们还有必要拓展Y节点么?

综上所述,采用BFS方法,在每一层中,如果出现余数相同的节点,只需要拓展最先出现的即可。

《编程之美》介绍的是另一种更妙的方法。

枚举M也好,BFS搜索N * M也好,我们有没有想过N * M超出整数范围?难道对于大整数,我们还要手写一个大数类?好麻烦…………

首先要解决的是,对于大整数,我们如果表示呢?

因为结果N * M只包含1和0,我们可以用一个vector保留1出现的位数。比如11001,可以用 {0 3 4} 表示。这种方法很省空间。

回想一下刚才提到的,BFS的剪枝方法——同余的数只保留最小的!

看个实例大家就好懂了:

如果知道100 mod 3 =1

10 mod 3 = 1

1 mod 3 = 1

110 mod 3 = 2

如何找到比110更小而且mod 3 = 2的数呢?用1去替换110中的10就OK了。因为1和10同余,所以保留余数最小的即可,毕竟我们找的是满足mod N = 0最小且只含有0和1的数。

我的代码如下:

#include <iostream>
#include <vector>
using namespace std;

void display(vector<int> &v)
{
int t = 0;
for (int i = v.size() - 1;i >= 0;i--)
{
t = v[i];
cout << '1';
while(i > 0 && --t != v[i - 1])
cout << '0';
}
while(t--)
cout << '0';
cout << endl;
}
void searchTheNum(vector<vector<int>> &v, int n)
{
for (int i = 0;i < n;i++)
{
vector<int> nv;
nv.clear();
v.push_back(nv);
}
v[1].push_back(0);
int j;
for (int i = 1, j = 10 % n; ;i++, j = (j * 10) % n)
{
if (0 == v[j].size())
{
v[j].push_back(i);
}
for (int k = 0;k < v.size();k++)
{
if (v[k].size() > 0
&& v[(k + j) % n].size() == 0
&& i > v[k][v[k].size() - 1])
{
v[(k + j) % n] = v[k];
v[(k + j) % n].push_back(i);
}
}

if (v[0].size())
{
display(v[0]);
return;
}
}
}
int main()
{
vector<vector<int>> v;
int n = 99;
searchTheNum(v, n);
return 0;
}


对于书中的拓展问题1:

对于任意的N,一定存在M,使得N*M的乘积的十进制表示只有0和1吗?

我百度到的答案是肯定存在,所以我的代码就假设一定存在解。

实际上书中的代码用了抽屉原理判断是否有解。

拓展问题2:

怎么找出满足题目要求的N 和 M,使得N * M < 2的16次方,且N + M最大?

根据N定出M的上界,并在这个范围内进行查找。

用如上的思路都可以解决。

BFS:先拓展值较大的点,每层同余的数只保留值大的。

书中的方法:也是要保留大值。

这些都还要加上边界的判断。

参考资料:

《编程之美》 2.8 找符合条件的整数

/article/4952676.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: