poj-1426
2014-07-21 20:54
169 查看
// 596K 32MS G++ #include <cstdio> #include <string> #include <cstring> #include <queue> using namespace std; #define MAX1 45 #define MAX_R 100000 struct BFSNode{ int digitCapacity; int reminderArraySize; int reminderArray[MAX1]; // mod 100000 when curVal exceed 100000 int curVal; // store the val which after processde by reminderArray int Reminder; }; int Num; typedef struct BFSNode BFSNode; queue<BFSNode> BFSQueue; int getDigitCapacity(int num) { int res = 0; while(num) { res++; num /= 10; } return res; } char fragment[32][6] = { "00000", "00001","00010","00011", "00100", "00101","00110","00111", "01000", "01001","01010","01011", "01100", "01101","01110","01111", "10000", "10001","10010","10011", "10100", "10101","10110","10111", "11000", "11001","11010","11011", "11100", "11101","11110","11111" }; char BFSFlag[300]; char BFS() { while (BFSQueue.size()) { BFSQueue.pop(); } BFSNode begiNode; begiNode.curVal = 1; begiNode.digitCapacity = 1; begiNode.reminderArraySize = 0; memset(begiNode.reminderArray, 0 ,sizeof(begiNode.reminderArray)); memset(BFSFlag, 0, sizeof(BFSFlag)); begiNode.Reminder = 1 % Num; BFSFlag[begiNode.Reminder] = 1; BFSQueue.push(begiNode); while(BFSQueue.size()) { BFSNode curNode = BFSQueue.front(); BFSQueue.pop(); int curVal = curNode.curVal; int curDigitCapacity = curNode.digitCapacity; int curReminder = curNode.Reminder; // printf("R %d C %d Num %d\n", curReminder, curDigitCapacity, Num); int congruentNum = curReminder * 10; // check 0 if (congruentNum % Num == 0) { // find it ! for (int i = 0; i < curNode.reminderArraySize; i++) { // printf("%s", fragment[curNode.reminderArray[i]]); printf("%05d", curNode.reminderArray[i]); } int tmpD = getDigitCapacity(curVal*10); // printf("\n%d %d\n", tmpD, curDigitCapacity + 1); // if (tmpD < curDigitCapacity + 1) { // for (int i = 0; i < curDigitCapacity + 1 - tmpD; i++) { // printf("0"); // } // } printf("%0*d\n", curDigitCapacity + 1, curVal*10); return 1; } else { BFSNode newNode; newNode.Reminder = congruentNum % Num; if (!BFSFlag[newNode.Reminder]) { newNode.digitCapacity = curDigitCapacity + 1; BFSFlag[newNode.Reminder] = 1; // printf("%d -> %d\n", curReminder, newNode.Reminder); memcpy(newNode.reminderArray, curNode.reminderArray, sizeof(newNode.reminderArray)); newNode.reminderArraySize = curNode.reminderArraySize; int newVal = curVal * 10; if (newNode.digitCapacity > 5) { newNode.reminderArray[newNode.reminderArraySize] = newVal/10; newNode.reminderArraySize++; newNode.curVal = newVal%10; newNode.digitCapacity = 1; } else { newNode.curVal = newVal; } BFSQueue.push(newNode); } } // check 1 if ((congruentNum +1) % Num == 0) {// find it ! // printf("%d\n", congruentNum +1); for (int i = 0; i < curNode.reminderArraySize; i++) { // printf("%s", fragment[curNode.reminderArray[i]]); printf("%05d", curNode.reminderArray[i]); } int tmpD = getDigitCapacity(curVal*10 + 1); // printf("\n%d %d\n", tmpD, curDigitCapacity + 1); // if (tmpD < curDigitCapacity + 1) { // for (int i = 0; i < curDigitCapacity + 1 - tmpD; i++) { // printf("0"); // } // } printf("%0*d\n", curDigitCapacity + 1, curVal*10 + 1); return 1; } else { BFSNode newNode; newNode.Reminder = (congruentNum + 1) % Num; if (!BFSFlag[newNode.Reminder]) { BFSFlag[newNode.Reminder] = 1; newNode.digitCapacity = curDigitCapacity + 1; // printf("%d -> %d\n", curReminder, newNode.Reminder); memcpy(newNode.reminderArray, curNode.reminderArray, sizeof(newNode.reminderArray)); newNode.reminderArraySize = curNode.reminderArraySize; int newVal = curVal * 10 + 1; if (newNode.digitCapacity > 5) { // if digits has been 6 long newNode.reminderArray[newNode.reminderArraySize] = newVal/10; // printf("put %d %d\n", newNode.reminderArraySize, newNode.reminderArray[newNode.reminderArraySize]); newNode.reminderArraySize++; newNode.curVal = newVal%10; newNode.digitCapacity = 1; } else { newNode.curVal = newVal; } BFSQueue.push(newNode); } } } // printf("finished\n"); return 0; } void solve() { char res = BFS(); } char Only1OR0(int num) { while(num) { int lowest = num%10; if (lowest != 0 && lowest != 1) { return 0; } num = num/10; } return 1; } int main() { while(1) { scanf("%d", &Num); if (Num == 0) { return 0; } else if (Only1OR0(Num)) { printf("%d\n", Num); } else { solve(); } } }
很棒的一道题,
不看解答还真想不到这道题能用BFS解,其实BFS的思路倒是比较简单:
对于给定的数N
先从1位开始:只能选择 1(0不是合法解), 检查 1%N == 0,如果不行:
那么增加到两位: 10 ,11,再检查,如果不行:
增加到3位: 100, 101, 110, 111。。。。
就这样依次检查,每次扩展的新的数值 都是原来的两倍,等于每次BFS时,每个节点都有两条边到新的节点。
这就是基本的思路,但是会有很多实现的问题:
每次增加数位递增的数值在题目里最多会到200位,long long都搞不定(不过因为本题数据弱,真这么搞也行),首先想到的就是大数,
但是考虑到效率和内存占用,应该是满足不了本题的需求的,因此这时候,就需要伟大的同余定理出场了:
题目要求检查的其实就是能否被N整除,那么根据同余定理:
(aN + b)%N == ((a+x)N + b)%N, 即对于再大的数,在考察同余时(这里的整除表现为余数==0),都可以缩小为一个足够小的数。
在本题中,就这样做:
对某一次的在要检查的数X最后增加一位数(0/1),而增加的基础,也就是上一次的数(X)%N的余数 是 R,
那么有 X ==aN + R, 那么 在X后面增加一位数,其值就变为了 10*X(增加0)/10*X +1 (增加1),
这时候,就要检查了10*X/10*X+1 能否被N整除了,
10*X = 10*(aN + R) = 10 *aN + R*10, 而 (10 *aN + R*10)%N = R*10%N,R*10是一个足够小的可以直接用int表示的值(根据题意,R<=200),
这样就克服了增加数位后数值太大的问题了,10*X+1同理, 和 R*10 + 1同N余,
如果在增加了一位以后还不能整除N,那么记下这一次的余数R0/R1(这一次的数X就表示为 a1N + R0/R1), 在下一次增加数位的时候计算余数,
就这样,一直到找到了能整除N的数X。
BFSNode 里携带的信息要包含此次X%N的值,为检测两个新的BFSNode增加位后的X能否整除N.
除了上面这个问题外,还有另外一个问题:
最后要求输出能整除N的X,而X可能会很长,如果每个BFSNode中直接用字符串类型表示X,可能会MLE,
这时候,也需要一种表示方式能压缩X,可以这么做:
BFSNode中不用字符串数组保存,而是用int数组L,不同的是,L每个数组值保存的是X的5位值(其实5位保守了,完全可以10位,只要不超过int的范围就可以)。
举个例子: X 是 10010 00101 00011 01111, 一共有20位,那么可以分为4段,每一段直接数值保存在L数组中:
L数组内容就是: L[0] == 10010, L[1] == 00101, L[2] = 00011, L[3] = 01111, 这样就保存了X值,最后输出X的时候,顺序输出L即可,
一些实现细节就是,BFSNode要维护一个当前X的值V和当前的数位D,每次增加数位,D++,X*10/X*10+1, 如果D >5,那么就把X/10的值保存在L中,
而X值刷新为X%10, 注意最后输出的时候,要补0,比如L[1] = 10000, L[2] = 00000(数字是0), 那么输出时要 printf("%50d")补0. 不然就从 10000 00000 -> 10000 0了,最后剩余的不满5位的X也要注意这个问题。
其实上面这个也是不是最好的办法,最好的办法是直接上位,因为X只有1和0,因此完全可以用一位bit来保存X的某一位,
这样最多需要200位,并且,每次增加新数位的操作也很简单,只需左移一位就可以。
最后是一个优化的问题,
可以注意到,上面的求余数过程中,如果在某一次得到一个余数R, 另外一次也得到一个余数R, 两次的后继操作会一模一样,
这就说明了,在求X时,最多遍历所有的<N的余数,就可以得到X了,因此要加一个余数的FLAG,标示此余数之前是否出现过,如果出现过直接pass不处理(否则是一轮同样的操作),这样就大大减少了运算次数。
检测答案的时候,被python坑了,得到199的X其实对的,不过python因为精度问题,X/199没表示成整数,还是用了divmod才OK.
相关文章推荐
- poj 1426 Find The Multiple (bfs 搜索)
- POJ_1426_Find The Multiple
- POJ 1426 Find The Multiple
- POJ-1426 Find The Multiple ( BFS )
- poj 1426 dfs~
- POJ 1426 Find The Multiple——bfs + 模运算 + 打表
- Poj 1426 Find The Multiple
- poj1426解题报告
- 【POJ】1426 Find The Multiple(暴力|同余模定理|BFS)
- AYIT2017暑假集训第二周周三赛 A - Find The Multiple POJ - 1426
- POJ - 1426 Find The Multiple(深搜)
- Find The Multiple POJ - 1426
- POJ 1426-Find The Multiple
- problem-1426-poj
- POJ1426-Find The Multiple-深度优先搜索BFS
- POJ 1426 Find The Multiple
- POJ 1426 (BFS)
- POJ-1426(Find The Multiple)--简单搜索
- POJ 1426 字符串来处理大数求解该题
- POJ-1426(Find The Multiple) dfs