题目链接:poj 1426
Find The Multiple
Time Limit: 1000MS Memory Limit: 10000K
Special Judge
Description
Given a positive integer n, write a program to find out a nonzero multiple m of n whose decimal representation contains only the digits 0 and 1. You may assume that n is not greater than 200 and there is a corresponding m containing no more than 100 decimal digits.
Input
The input file may contain multiple test cases. Each line contains a value of n (1 <= n <= 200). A line containing a zero terminates the input.
Output
For each value of n in the input print a line containing the corresponding value of m. The decimal representation of m must not contain more than 100 digits. If there are multiple solutions for a given value of n, any one of them is acceptable.
Sample Input
2
6
19
0
Sample Output
10
100100100100100100
111111111111111111
给你一个n,让你找出一个数m,满足两个条件:
1.它的每一个数位不是1就是0;
2.它必须是n的倍数;
思路:搜索,先从最高位开始(最高位必为1),在末尾逐次加1或者0,每加一次都判断一次是否为n的倍数。然而写一半发现好像还要处理一下大数问题。略尴尬。于是默默滚去搜题解。
同余模定理:
将大数问题转化为模,每一步都计算新的模的值。
(a * b) % n = (a % n * b % n) % n
(a + b) % n = (a % n + b % n) % n
借用discuss里一位仁兄的话,本题树大解浅。说是树大,似乎dfs会比较有利,但是虽说最优解浅,却有多解,dfs得到的第一个解很可能是深解,本题只看题目的话估计出的解空间为2^100(当然实际上并没有这么大),找深解会浪费比较多的时间,这样分析的话bfs应该要更合适一些。
之前没写过dfs剪枝,暴力全搜必然各种炸,后来根据同余模定理和bfs的写法想到dfs就和它一样,遇到与之前同模的情况就剪掉,避免循环(就像走迷宫原地绕圈圈一样,徒增无用的计算)。
然后dfs 750ms卡过……直接在bfs的代码上改成了dfs,但由于dfs的特性,我这份dfs代码找解的时间整体要比bfs长。
最后就是discuss里面比较有意思的,大家都做过完了后发现bfs搜出来的最优解最大也就19位数,于是就有人直接用unsign long long写了暴力的dfs,解空间大于2^19就直接停止往下搜,时间缩短了很多,但总体来说这不是个常规解题思路,不知道这个数据范围卡的是不是出题者故意为之……然后还看见有人用自动机写???
discuss的代码:poj 1426 discuss 又短又暴力的dfs代码
bfs:
#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <ctime>
#include <cmath>
#include <queue>
#include <map>
#define M 205
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
string num;
int mod;
}st, tmp, t;
int n;
bool vis[M];
void bfs()
{
memset(vis, true, sizeof(vis));
st.mod = 1 % n;
queue<node> Q;
Q.push(st);
while(!Q.empty())
{
tmp = Q.front();
Q.pop();
int mod1 = (tmp.mod * (10 % n) + 1 % n) % n;//在末位加1
int mod2 = (tmp.mod * (10 % n)) % n;//在末位加0
if(mod1)
{
if(vis[mod1])
{
t = tmp;
t.num += "1";
t.mod = mod1;
vis[mod1] = false;
Q.push(t);
}
}
else
{
cout << tmp.num << "1" << endl;
break;
}
if(mod2)
{
if(vis[mod2])
{
t = tmp;
t.num += "0";
t.mod = mod2;
vis[mod2] = false;
Q.push(t);
}
}
else
{
cout << tmp.num << "0" << endl;
break;
}
}
}
int main()
{
st.num = "1";
while(scanf("%d", &n) && n)
{
bfs();
}
return 0;
}
运行结果:
dfs:
#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <ctime>
#include <cmath>
#include <queue>
#include <map>
#define M 205
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
string num;
int mod;
}st, tmp, t;
int n;
bool vis[M], flag;
void dfs(node tmp)
{
if(flag || tmp.num.size() > 100) return;
int mod1 = (tmp.mod * (10 % n) + 1 % n) % n;
int mod2 = (tmp.mod * (10 % n)) % n;
if(mod1)
{
if(vis[mod1])
{
t = tmp;
t.num += "1";
t.mod = mod1;
vis[mod1] = false;
dfs(t);
}
}
else if(tmp.num.size() < 100 && !flag)
{
cout << tmp.num << "1" << endl;
flag = true;
}
if(mod2)
{
if(vis[mod2])
{
t = tmp;
t.num += "0";
t.mod = mod2;
vis[mod2] = false;
dfs(t);
}
}
else if(tmp.num.size() < 100 && !flag)
{
cout << tmp.num << "0" << endl;
flag = true;
}
vis[mod1] = vis[mod2] = true;//回溯,若直接写在dfs语句后面,某些情境下会死循环。
}
int main()
{
st.num = "1";
while(scanf("%d", &n) && n)
{
memset(vis, true, sizeof(vis));
flag = false;
st.mod = 1 % n;
dfs(st);
}
return 0;
}
运行结果: