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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM