zoukankan      html  css  js  c++  java
  • 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
    ", 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
  • 相关阅读:
    一个关于css3背景透明的例子
    原生js写的一个当前年份日期星期和时间的显示
    一个原生js写的加减乘除运算
    风行一时瀑布流网页布局,实现无限加载(jquery)
    bootstrap你让前端小狮子们又喜又恨
    潭州课堂25班:Ph201805201 django 项目 第二十一课 文章主页 新闻列表页面功能 (课堂笔记)
    潭州课堂25班:Ph201805201 django 项目 第二十课 数据库分析设计图 (课堂笔记)
    潭州课堂25班:Ph201805201 django 项目 第十九课 文章主页数据库模型,前后台功能实现 (课堂笔记)
    潭州课堂25班:Ph201805201 django 项目 第十八课 前台 注解 (课堂笔记)
    潭州课堂25班:Ph201805201 django 项目 第十七课 用户登录,登出实现 (课堂笔记)
  • 原文地址:https://www.cnblogs.com/Rorshach/p/9352275.html
Copyright © 2011-2022 走看看