zoukankan      html  css  js  c++  java
  • 数论——裴蜀定理

    裴蜀定理

    设 a,b是不全为零的整数,则存在整数 x,y, 使得 a*x+b*y=gcd(a,b) .

    证明过程略

    应用

    给出 n张卡片,分别有li和ci。在一条无限长的纸带上,你可以选择花ci 的钱来购买卡片i,从此以后可以向左或向右跳li个单位。问你至少花多少元钱才能够跳到纸带上全部位置。若不行,输出-1

    解析:

    分析该问题,先考虑两个数的情况,发现想要跳到每一个格子上,必须使得这些数通过数次相加或相加得出的绝对值为1 ,进而想到了裴蜀定理。

    可以推出:如果a与b互质,那么一定存在两个整数x与y,使得ax+by=1 .

    由此得出了若选择的卡牌的数通过数次相加或相减得出的绝对值为1,那么这些数一定互质,此时可以考虑动态规划求解。

    不过可以转移思想,因为这些数互质,即为0号节点开始,每走一步求 gcd(节点号,下一个节点),同时记录代价,就成为了从0 通过不断gcd最后变为1的最小代价。

    由于:互质即为最大公因数为1,gcd(0,x)=x 这两个定理,可以证明该算法的正确。选择优先队列优化 Dijkstra 求解。

    不过还有个问题,即为需要记录是否已经买过一个卡片,开数组标记由于数据范围达到 10^9会超出内存限制,可以想到使用 unordered_map 

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath> 
    #include<map>
    #include<queue>
    #include<string> 
    #include<iostream>
    #include<stack>
    #define ll long long
    #define inf 0x3f3f3f3f
    template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
    template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
    using namespace std;
    const int N=303,M=0,Z=1e9+7,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143;
    const double eps=1e-8,PI=acos(-1.0);//.0
    map<int,int>mop;
    map<int,int>::iterator it;
    int l[N],c[N];
    int n;
    int gcd(int x,int y)
    {
        int z;
        while(y)
        {
            z=x%y;
            x=y;
            y=z;
        }
        return x;
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            mop.clear();
            for(int i=1;i<=n;i++)scanf("%d",&l[i]);
            for(int i=1;i<=n;i++)scanf("%d",&c[i]);
            for(int i=1;i<=n;i++)
            {
                for(it=mop.begin();it!=mop.end();it++)
                {
                    int x=it->first;
                    int y=it->second;
                    int g=gcd(l[i],x);
                    if(mop.find(g)==mop.end())mop[g]=y+c[i];
                    else gmin(mop[g],y+c[i]);
                }
                if(mop.find(l[i])==mop.end())mop[l[i]]=c[i];
                else gmin(mop[l[i]],c[i]);
            }
            if(mop.find(1)==mop.end())printf("-1
    ");
            else printf("%d
    ",mop[1]);
        }
        return 0;
    }
  • 相关阅读:
    类的加载与ClassLoader的理解
    反射:获取Class 类的实例(四种方法)
    磁盘调度算法
    死锁检测算法
    银行家算法
    最低松弛度调度算法模拟
    多级反馈队列调度算法
    内存中:请求调页存储管理方式的模拟
    内存的动态分区分配方式的模拟
    “短进程优先”调度算法
  • 原文地址:https://www.cnblogs.com/2462478392Lee/p/12459710.html
Copyright © 2011-2022 走看看