您的位置:首页 > 其它

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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: