Description
有两个数a、b,初始值分别为x、1,每次可以将a、b中的一个数与自身或另外一个进行乘、除运算,并将结果保存到a或b,求最少用多少次运算能得到x^P。 (P <= 20000)
Analysis
1、广度优先搜索
状态(a,b)代表(x^a, x^b),令a为二者中较大的数,从(a, b)可以转移到8个状态,即(2a, b)、(a+b,b)、(2b,b)、(a,2a)、(a,a+b)、(a,2b)、(a,a-b)、(a-b,a),分别将这8种状态加入队列继续进行搜索,直到a或b等于P。
2、A搜索
设计估价函数f(i) = g(i) + h(i),g(i)是当前步数。h(i)是当前状态到终点步数的预估值。
对于当前状态(a,b),当a小于P式,a成倍地增长(a=2, 即x^a和自己不断地相乘)可以更快的到达P,然后再用减法进行微调, h(i) = log(P/a);当a > P时,由于无法确定减法的次数,为了使h小于实际值,设h(i) = 0。用(a,b,g,h)表示状态,每次取g + h最小的状态进行扩展。
Code
bfs + 剪枝
5312K 485MS
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 20003, maxq = 700003, prime0 = 20101, prime1 = 97;
int n, n2, answer;
bool hashTable[prime0][prime1];
struct node{
int a, b, step;
};
queue<node> q;
int gcd (int a, int b) { return b ? gcd (b, a % b) : a; }
bool add_node(int a,int b,int step)
{
if (a == n || b == n)
return true;
if (a < b)
{
int temp = a;
a = b;
b = temp;
}
if (n % gcd (a, b)) return false;
if (a > 2 * n) return false;
if (a > n && b == 0) return false;
if (a == b || a >= n2 || b >= prime1)
return false;
if (!hashTable[a][b])
{
hashTable[a][b] = true;
q. push ({a, b, step});
}
return false;
}
int bfs() {
n2 = n + prime1;
add_node(1, 0, 0);
while(!q.empty())
{
int a = q.front().a, b = q.front().b, step = q.front().step + 1;
q.pop();
if(add_node(a+a, b, step) ||
add_node(a+b, b, step) ||
add_node(b+b, b, step) ||
add_node(a, a+a, step) ||
add_node(a, a+b, step) ||
add_node(a, b+b, step) ||
add_node(a, a-b, step) ||
add_node(a-b, a, step))
{
answer = step;
break;
}
}
return 0;
}
int main()
{
cin >> n;
bfs();
cout << answer;
return 0;
}
A* + 剪枝
9776K 47MS
#include <iostream>
#include <queue>
using namespace std;
const int prime0 = 20101, prime1 = 1097;
int n, n2, ans;
bool hashTable[prime0 + prime1][prime1];
struct node{
int a, b, g, h;
bool operator< (const node &a) const {
return g + h == a . g + a . h ? h > a . h : g + h > a . g + a . h;
}
};
node Now;
priority_queue<node> q;
int gcd (int a, int b) { return b ? gcd (b, a % b) : a; }
bool add_node(int a,int b) {
if (a == n || b == n)
return true;
if (a < b) {
int temp = a;
a = b;
b = temp;
}
if (a > 2 * n) return false;
if (a > n && b == 0) return false;
if (a == b) return false;
if (n % gcd (a, b)) return false;
if (a >= n2 || b >= prime1)
return false;
if (!hashTable[a][b]) {
hashTable[a][b] = true;
int h = 0, tx = a;
while (tx < n) h ++, tx <<= 1;
q. push ({a, b, Now.g + 1, h});
}
return false;
}
int Astar() {
n2 = n + prime1;
q. push({1, 0, 0, 0});
hashTable[1][0] = true;
while(!q.empty()) {
Now = q.top();
int a = Now.a, b = Now.b;
q.pop();
if(add_node(a+a, b) || add_node(a+b, b) || add_node(b+b, b) || add_node(a, a+a) ||
add_node(a, a+b) || add_node(a, b+b) || add_node(a, a-b) || add_node(a-b, a)) {
ans = Now.g + 1;
break;
}
}
return 0;
}
int main() {
cin >> n;
Astar();
cout << ans;
return 0;
}