• qbzt day2 晚上(竟然还有晚上)


    内容提要

    搜索

    拓展欧几里得

    逆元


    先是搜索

    A*

     

    有几个数组

    g 当前点到根节点的深度

    h 当前点到终点理想的最优情况需要走几步

    f  f=g+h

    A*就是把所有的f从小到大排序

    启发式搜索相较于其他的搜索的优势在于引入了一个启发式函数f(x) = g(x) +h(x)

    g*(x) : 从 S 到 x 的理论最近距离

    g(x) : 对 S 到 x 对于 g*(x) 的估计

    f*(x) : 从 x 到 T 的理论最近距离,F*(x)=g*(x)+h*(x)

    f(x) : 从 x 到 T 对于 f*(x) 的估计,F(x)=g(x)+h(x)

    可以理解为:带*的是开挂的,不带*的是真实的

    当满足 f(x) <= f*(x) 时,总能找到最优解

     

    和 BFS 几乎一样,只是每次都弹出当前局面中f(x)最小的那个局面进行扩展

    ——故需要维护一个优先队列(小根堆)

    ——使用系统的priority_queue<>即可

    当 f(x) = g(x) + h(x) 中 h(x) = 0 即失去了启发式函数,则变为Breath First Search

    当 f(x) = g(x) + h(x) 中 g(x) = 0 则变为 Best First Search

    当第一次到终点的时候就输出g(x)就可以了

     

    例题:八数码

    如何告诉计算机某种情况已经到达过呢:

    如何做到将一个 1~n 的排列与一个整数做一一对应?

    或者更直白的:

    如何求出字典序第 k 的排列?

    如何求出一个排列在字典序中排第几?

    这样数组只需要开9!=36880

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    const int sizeofpoint=1024;
    const int sizeofedge=262144;
    
    int N, M;
    int S, T, K;
    int d[sizeofpoint], t[sizeofpoint];
    
    struct node
    {
        int u; int g;
    
        inline node(int _u, int _g):u(_u), g(_g) {}
    };
    inline bool operator > (const node & , const node & );
    
    struct edge
    {
        int point; int dist;
        edge * next;
    };
    inline edge * newedge(int, int, edge * );
    inline void link(int, int, int);
    edge memory[sizeofedge], * port=memory;
    edge * e[sizeofpoint], * f[sizeofpoint];
    std::priority_queue<node, std::vector<node>, std::greater<node> > h;
    
    inline int getint();
    inline void dijkstra(int);
    inline int Astar();
    
    int main()
    {
        N=getint(), M=getint();
        for (int i=1;i<=M;i++)
        {
            int u=getint(), v=getint(), d=getint();
            link(u, v, d);
        }
        S=getint(), T=getint(), K=getint();
        dijkstra(T);
    
        if (d[S]==-1)
        {
            puts("-1");
            return 0;
        }
    
        K+=S==T;
    
        printf("%d
    ", Astar());
    
        return 0;
    }
    
    inline bool operator > (const node & u, const node & v)
    {
        return (u.g+d[u.u])>(v.g+d[v.u]);
    }
    
    inline edge * newedge(int point, int dist, edge * next)
    {
        edge * ret=port++;
        ret->point=point, ret->dist=dist, ret->next=next;
        return ret;
    }
    inline void link(int u, int v, int d)
    {
        e[v]=newedge(u, d, e[v]);
        f[u]=newedge(v, d, f[u]);
    }
    
    inline int getint()
    {
        register int num=0;
        register char ch;
        do ch=getchar(); while (ch<'0' || ch>'9');
        do num=num*10+ch-'0', ch=getchar(); while (ch>='0' && ch<='9');
        return num;
    }
    inline void dijkstra(int S)
    {
        static int q[sizeofedge];
        static bool b[sizeofpoint];
        int l=0, r=0;
    
        memset(d, 0xFF, sizeof(d)), d[S]=0;
        for (q[r++]=S, b[S]=true;l<r;l++)
        {
            int u=q[l]; b[u]=false;
            for (edge * i=e[u];i;i=i->next) if (d[i->point]==-1 || d[u]+i->dist<d[i->point])
            {
                d[i->point]=d[u]+i->dist;
                if (!b[i->point])
                {
                    b[i->point]=true;
                    q[r++]=i->point;
                }
            }
        }
    }
    inline int Astar()
    {
        h.push(node(S, 0));
        while (!h.empty())
        {
            node p=h.top(); h.pop();
            ++t[p.u];
            if (p.u==T && t[T]==K)
                return p.g;
            if (t[p.u]>K)
                continue;
            for (edge * i=f[p.u];i;i=i->next)
                h.push(node(i->point, p.g+i->dist));
        }
        return -1;
    }

     

    IDA*

     

    g:从根节点往下几步

     

    h:步数

     

     

     

    g+h>d return

     

    双向A*?双向IDA*?

     

    h(x)>h*(x)?

     

    事实上h(x)与h*(x)的关系隐形决定了A*的运行速度与准确度

     

    h(x)越接近h*(x)跑得越快

     

     

     

    拓展欧几里得

     

    裴蜀定理:(x, y) = d ===> 存在无限多组整数 a,b:ax + by = d

     

     

     

    证明:计算机竞赛不需要证明

     

     

     

    扩展欧几里得算法可以帮助我们计算出 (x, y) = d 时一组 a,b:

     

     

    什么?你问为什么?这么短的代码你背下来不就好了嘛?

     

    扩展欧几里得算法有什么用呢?——计算逆元

     

    逆元的定义:如果 x 对 p 有一个逆元 y,则 x * y == 1 (mod p)

     

    x 对一个数 p 有逆元当且仅当 (x, p) = 1

     

    意义:在取模意义下做除法

     

    由裴蜀定理:存在 a, b 满足:ax + bp = 1

     

    嗯……,等等,岂不是 ax == 1 (mod p)

    计算组合数模p

    中国剩余定理

     

    问题、求余方程组 x = ai (mod pi)

     

    不多说,背代码:

    令 P = p1 * p2 * ... * pn

    令 Pi = P / pi

    令 Qi = Pi 对 pi 的逆元

     

    则 x = sigma(ai * Pi * Qi)

     

  • 相关阅读:
    P4549 【模板】裴蜀定理
    POJ1606 Jugs
    2. 数据库连接池规范
    14. BootStrap * 组件
    BootStarpt
    13. Flex 弹性布局2 BootStrap
    12. Flex 弹性布局 BootStrap
    CSS3
    21. Servlet3.0 / 3.1 文件上传 Plus
    20. Servlet3.0 新特性
  • 原文地址:https://www.cnblogs.com/lcezych/p/11185568.html
Copyright © 2020-2023  润新知