poj3373 Changing Digits
经过几天不屈不挠地思考这一题,最后还是不会,主要是想不到判重的方法。看了解题报告,正确来说,是代码。然后发现一直想不通的问题竟然是那么简单地被解决(用余数判重)。这个涉及到模n同余的特性。另外的两点就是搜索的顺序和高精度。搜索的话要按照以下规则:
1.从最高位开始,逐渐往低位搜;
2.先搜小于原来的数的,然后搜大于原来的数的;
3.先搜一位,然后两位,如此类推。
这样一来就可以保证第一个搜到的答案就是要求的答案。但是就这样直接算的话,还是会超时。所以需要优化一下。主要优化的地方就是求大数的余数的方法。
后记:
1.以后涉及大数的搜索,可以考虑用余数来表示状态。
===========分割线==================
-
#include <iostream>
-
#include <cstring>
-
using namespace std;
-
-
#define len 101
-
#define Max 10001
-
/*
-
remainder和q组成一个队列,表示当前的余数和数;
-
w[i][j]表示数字i在第j位上是对应k的余数
-
*/
-
int k, head, tail, l, w[11][len];
-
bool found, hash[Max];
-
-
struct longlong
-
{
-
int p[len], sp;
-
void convert(char *n);
-
int operator%(int d);
-
int& operator[](int i){return p[i];}
-
void clear();
-
void print() const;
-
}in, ans, tmp;
-
-
struct Qnode
-
{
-
longlong num;
-
int t, l;
-
int& operator[](int i){return num[i];}
-
}q[Max];
-
-
void longlong::convert(char *n)
-
{
-
int i, size;
-
-
size = strlen(n);
-
-
for (i = size - 1, sp = len - 1; i >= 0; i--, sp--) p[sp] = n[i] - '0';
-
-
sp++;
-
}
-
-
int longlong::operator %(int d)
-
{
-
int remainder = 0, sum, now = sp;
-
-
while (now < len)
-
{
-
sum = remainder;
-
do
-
{
-
sum = 10 * sum + p[now++];
-
}while (sum < d && now < len);
-
-
remainder = sum % d;
-
}
-
-
return remainder;
-
}
-
-
void longlong::clear()
-
{
-
memset(p, 0, sizeof(p));
-
sp = len - 1;
-
}
-
-
void longlong::print() const
-
{
-
int i;
-
-
for (i = sp; i < len; i++) cout << p[i];
-
-
cout << endl;
-
}
-
-
//通过递归有顺序地搜索,一次回溯只改变一位,从而保证第一个解为最优解
-
//用余数来判重
-
void backtrack(int i)
-
{
-
if (found) return;
-
-
int t;
-
for (tmp[i] = 0; tmp[i] < 10; tmp[i]++)
-
{
-
//no leading zero
-
if (!tmp[i] && i == tmp.sp) continue;
-
-
if (tmp[i] == q[head][i])
-
{
-
if (i < len - 1) backtrack(i + 1);
-
continue;
-
}
-
-
t = (q[head].t + w[tmp[i]][i] - w[q[head][i]][i] + k) % k;
-
-
if (!t && !found)
-
{
-
found = true;
-
ans = tmp;
-
-
return;
-
}
-
else
-
{
-
if (t && !hash[t])
-
{
-
hash[t] = true;
-
q[tail].t = t;
-
q[tail++].num = tmp;
-
}
-
}
-
}
-
-
tmp[i] = q[head][i];
-
}
-
-
void BFS()
-
{
-
//initialize
-
int i, j;
-
for (i = 0; i < 10; i++)
-
{
-
w[i][len - 1] = i % k;
-
for (j = len - 2; j >= in.sp; j--) w[i][j] = w[i][j + 1] * 10 % k;
-
}
-
-
memset(hash, 0, sizeof(hash));
-
found = false;
-
head = tail = l = 0;
-
-
//solve
-
int t, sp = in.sp;
-
-
t = in % k;
-
-
if (!t)
-
{
-
ans = in;
-
return;
-
}
-
else if (in.sp == len - 1)
-
{
-
ans.sp = in.sp;
-
ans[ans.sp] = 0;
-
return;
-
}
-
-
q[tail].num = in;
-
q[tail].l = 0;
-
q[tail++].t = t;
-
hash[t] = true;
-
-
while (head < tail)
-
{
-
tmp = q[head].num;
-
q[head].l++;
-
-
if (q[head].l < 6) backtrack(sp);
-
if (found) return;
-
-
head++;
-
}
-
}
-
-
int main()
-
{
-
char n[101];
-
-
while (scanf("%s", n) != EOF)
-
{
-
scanf("%d", &k);
-
-
in.convert(n);
-
BFS();
-
ans.print();
-
ans.clear();
-
tmp.clear();
-
}
-
-
return 0;
-
}
-