这题搞了我好几天。。算是做过的搜索题中对时间要求比较苛刻的了,算法稍微差点就超时。。优化了好久,开始队列里面存的是指针,状态都是新new的,这样无论怎么优化都超时。。后来参考了网上代码,把状态全放到一个大数组里面,这样每次搜的时候直接数组寻址就行了,不用再new对象,这样能险险AC,用时6s,总的来说本题就是BFS加状态压缩,状态由两个组成,一是当前余数,范围为1到1000,二是当时用过的数字,用一个二进制位表示数字是否用到,那么状态范围就是0到1<<10, 两种状态组合就是1000*1024种状态,开始就把状态用数组初始化好,然后队列里搜的时候就能直接用数组下标要记录状态了。。最后,祝自己生日快乐,happy every day!!!
#include<cstdio>
#include<deque>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<cstdlib>
using namespace std;
namespace
{
struct Num
{
char c;
pair<int, int> prev;
bool flag;
} N[1000][1 << 10];
int n, m;
deque<pair<int, int> > Q;
vector<int> V;
vector<char> C;
void init()
{
for (int i = 0; i < 10; i++)
{
V.push_back(1 << i);
C.push_back('0' + i);
}
}
int digit(int bit)
{
int count = 0;
while (bit)
{
if (bit & 1)
count++;
bit >>= 1;
}
return count;
}
string& remove_leading_zero(string &s)
{
while (s[0] == '0')
s.erase(0, 1);
return s;
}
string divide(const string &s, int n)
{
string t = "0";
int rem = 0;
for (size_t i = 0; i < s.size(); i++)
{
rem = rem * 10 + (s[i] - '0');
t += (rem / n + '0');
rem = rem % n;
}
return remove_leading_zero(t);
}
string append(pair<int, int> p)
{
string s;
while (p.first || p.second)
{
s = N[p.first][p.second].c + s;
p = N[p.first][p.second].prev;
}
return s;
}
void bfs()
{
memset(N, 0, sizeof(N));
Q.clear();
Q.push_back(make_pair(0, 0));
N[0][0].flag = true;
bool find = false;
while (!Q.empty() && !find)
{
pair<int, int> p = Q.front();
char c = N[p.first][p.second].c;
int rem = p.first;
int bit = p.second;
Q.pop_front();
for (int i = (c ? 0 : 1); i < 10; i++)
{
int r = (rem * 10 + i) % n;
int b = bit | V[i];
int dd = digit(b);
if (!r && dd == m)
{
find = true;
string ss = append(p) + C[i];
printf("%s=%d*%s\n", ss.c_str(), n, divide(ss, n).c_str());
break;
}
else if (!(N[r][b].flag) && dd <= m)
{
N[r][b].flag = true;
N[r][b].prev = p;
N[r][b].c = C[i];
Q.push_back(make_pair(r, b));
}
}
}
if (!find)
puts("Impossible");
}
}
int main()
{
init();
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d %d", &n, &m);
bfs();
}
return 0;
}