UVA 1341 - Different Digits
题意:给定一个正整数n。求一个kn使得kn上用的数字最少。假设同样,则输出值最小的
思路:
首先利用鸽笼原理证明最多须要2个数字去组成
设一个数字k。组成k,kk,kkk,kkkk... %n之后余数必定在0 - (n - 1)之间,所以必定能选出两个余数相等的数字相减为0,这个数字就是由0和k组成的。
因此仅仅要考虑一个数字和两个数字的情况,去bfs。记忆化余数。由于余数反复必定形成周期了
代码:
#include <stdio.h> #include <string.h> const int INF = 0x3f3f3f3f; const int N = 66666; int n, num[2], vis[N], ans, save[N]; struct Queue { int mod, pre, num, len; Queue(){} Queue(int mod, int pre, int num, int len) { this->mod = mod; this->pre = pre; this->num = num; this->len = len; } } q[N * 2]; void out(int now, int d) { if (now == -1) return; out(q[now].pre, d - 1); save[d] = q[now].num; } int judge(int now, int d) { if (now == -1) return 0; int tmp = judge(q[now].pre, d - 1); if (tmp != 0) return tmp; if (save[d] == q[now].num) return 0; else if (q[now].num < save[d]) return -1; else return 1; } void bfs() { int head = 0, tail = 0; if (num[0] != 0) { q[tail++] = Queue(num[0] % n, -1, num[0], 1); vis[num[0] % n] = 1; } if (num[1] != -1 && num[1] != 0) { q[tail++] = Queue(num[1] % n, -1, num[1], 1); vis[num[1] % n] = 1; } while (head < tail) { Queue now = q[head]; if (now.len > ans) return; if (now.mod == 0) { if (now.len <= ans) { if (now.len != ans || judge(head, ans - 1) < 0) { ans = now.len; out(head, ans - 1); } } } Queue next; for (int i = 0; i < 2; i++) { if (num[i] == -1) continue; next = Queue((now.mod * 10 + num[i]) % n, head, num[i], now.len + 1); if (vis[next.mod]) continue; vis[next.mod] = 1; q[tail++] = next; } head++; } } int main() { while (~scanf("%d", &n) && n) { ans = INF; for (int i = 1; i < 10; i++) { num[0] = i; num[1] = -1; memset(vis, 0, sizeof(vis)); bfs(); } if (ans == INF) { for (int i = 0; i < 10; i++) { for (int j = i + 1; j < 10; j++) { num[0] = i; num[1] = j; memset(vis, 0, sizeof(vis)); bfs(); } } } for (int i = 0; i < ans; i++) printf("%d", save[i]); printf(" "); } return 0; }