poj 1945 Power Hungry Cows A*

Description:

    就是给你一个数,你可以把它自乘,也可以把他乘或除以任意一个造出过的数,问你最多经过多少次操作能变换成目标数

思路:这题真的不怎么会啊。n = 20000,每一层都有很多个扩展状态,裸宽搜会被T,启发式函数又设计不出来……

看了一个Vjudge上的代码才知道这题怎么写。

就是每一个状态是由最多两个数转化而来的,所以可以把两个数看做一个状态。

用一个多元组$node(x,y,g,h)$表示状态,$x, y$分别表示两个数中的较大数和较小数,然后$g$表示转换成当前的状态需要多少步,$h$表示大数$x$转换到大于等于目标状态至少还要多少步。

启发式函数就是当前步数+预期至少需要的步数,即$g+h$

再用一个哈希表把二元组$(x,y)$与转换到这个状态需要几步对应起来,这样可以完成去重。当然也可以用$map$实现,但按照poj的尿性,很可能TLE。。

然后加几个剪枝,排除以下多余状态:

1.如果$x > 2*n$,这个都能理解吧。

2.如果$x=y$,因为该状态和一个$x$的状态对未来的贡献是等价的,反正自乘自除也能达到一样的效果,不管$y$取什么数,都比$x$与$y$相等时更优。

3.如果$x > n$ 并且 $y = 0$,因为这样的话该状态永远达不到$x=n$。

4.如果$n $ $mod$ $gcd(x,y) != 0$,因为这样的状态不管怎么乘怎么除,也永远达不到$x=n$。

5.如果$(x,y)$已经在哈希表里了且对应的$g$更小,这个也都能理解吧。

这样的话就应该能过了。

然后款搜的时候要注意下,枚举出一个二元组能变换出来的所有可能的二元组,这个具体可以看代码。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<queue>
 5 using namespace std;
 6 const int N = 30007, SIZE = 1e6 + 10;
 7 int n;
 8 struct node{
 9     int x, y, g, h;
10     bool operator < (const node &a)const{
11         return g + h == a.g + a.h ? h > a.h : g + h > a.g + a.h;
12     }
13 };
14 struct Node{
15     int to, next, w;
16 };
17 struct hash_map{
18     int head[N], now;
19     Node a[SIZE];
20     bool insert(int sta, int w){
21         int x = sta % N;
22         for(int i = head[x]; i; i = a[i].next){
23             if(a[i].to == sta){
24                 if(a[i].w <= w) return 0;
25                 a[i].w = w; return 1;
26             }
27         }
28         a[++now] = {sta, head[x], w};
29         head[x] = now;
30         return 1;
31     }
32 }dict;
33 priority_queue<node> heap;
34 node now;
35 int gcd(int a, int b){ return b ? gcd(b, a % b) : a;}
36 void che(int x, int y){
37     if(x < y) swap(x, y);
38     if(x > 2 * n) return ;
39     if(x > n && y == 0) return ;
40     if(x == y) return ;
41     if(n % gcd(x, y)) return;
42     if(!dict.insert(x * 50000 + y, now.g + 1)) return;
43     int h = 0, tx = x;
44     while(tx < n) h++, tx <<= 1;
45     heap.push({x, y, now.g + 1, h});
46 }
47 void A_star(){
48     heap.push({1, 0, 0, 0});
49     while(!heap.empty()){
50         now = heap.top(); heap.pop();
51         if(now.x == n || now.y == n){
52             printf("%d\n", now.g); break;
53         }
54         int a[2] = {now.x, now.y};
55         for(int i = 0; i < 2; i++)
56           for(int j = i; j < 2; j++)
57             for(int k = 0; k < 2; k++){
58                 int b[2] = {a[0], a[1]};
59                 b[k] = a[i] + a[j];
60                 che(b[0], b[1]);
61             }
62         che(now.x - now.y, now.y);
63         che(now.x, now.x - now.y);
64     }
65 }
66 int main(){
67     scanf("%d", &n);
68     A_star();
69     return 0;
70 }
View Code

猜你喜欢

转载自www.cnblogs.com/Rorshach/p/9352275.html