• POJ 1945 Power Hungry Cows


    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;
    }
    
  • 相关阅读:
    3Sum Closest
    二叉树的下一个结点
    数组中重复的数字
    不用加减乘除做加法
    和为S的连续正数序列
    数组中只出现一次的数字
    求二叉树的是否为平衡二叉树
    由一道很简单的求两条链表的第一个公共节点的问题引发的思考
    第14章 网络编程
    第13章 文档与串行化
  • 原文地址:https://www.cnblogs.com/Zforw/p/16394356.html
Copyright © 2020-2023  润新知