zoukankan      html  css  js  c++  java
  • POJ 1860 Bellman-Ford算法

    转载链接:http://blog.csdn.net/lyy289065406/article/details/6645778

    提示:关键在于反向利用Bellman-Ford算法

    题目大意

    有多种汇币,汇币之间可以交换,这需要手续费,当你用100A币交换B币时,A到B的汇率是29.75,手续费是0.39,那么你可以得到(100 - 0.39) * 29.75 = 2963.3975 B币。问s币的金额经过交换最终得到的s币金额数能否增加

    货币的交换是可以重复多次的,所以我们需要找出是否存在正权回路,且最后得到的s金额是增加的

    怎么找正权回路呢?(正权回路:在这一回路上,顶点的权值能不断增加即能一直进行松弛)

    题目分析:

    一种货币就是图上的一个点

    一个“兑换点”就是图上两种货币之间的一个兑换环,相当于“兑换方式”M的个数,是双边

    唯一值得注意的是权值,当拥有货币A的数量为V时,A到A的权值为K,即没有兑换

    而A到B的权值为(V-Cab)*Rab

    本题是“求最大路径”,之所以被归类为“求最小路径”是因为本题题恰恰与bellman-Ford算法的松弛条件相反,求的是能无限松弛的最大正权路径,但是依然能够利用bellman-Ford的思想去解题。

    因此初始化d(S)=V   而源点到其他店的距离(权值)初始化为无穷小(0),当s到其他某点的距离能不断变大时,说明存在最大路径

     附个人代码:(POJ貌似是挂了。。。无限循环CE。。。。宝宝要哭了。。。。T_T)

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    using namespace std;

    int n, m, fn; // 分别表示货币种数 、 转换点 、 源点 、 源点权值
    double fv;
    double dis[210];

    struct Node
    {
        int u, v;
        double r, c; // c 兑换费用 r 兑换率
    }edge[210];

    int tot = 0;  // 边数  n 是点数

    bool relax(int j)
    {
        double t = (dis[edge[j].u] - edge[j].c) * edge[j].r;
        if (dis[edge[j].v] < t)  // 与bellman 算法刚好相反。bellman算法用来找找负环 求最短路径
        {                        //这里用同样的思想找正环 求最长路径
            dis[edge[j].v] = t;
            return true;
        }
        return false;
    }

    bool bellman(int ori)
    {
        memset(dis, 0, sizeof(dis));
        dis[ori] = fv;
        bool flag;
        for (int i=0; i<n; ++i)  // 尝试n-1次(对每个点一次) 对每条边进行松弛。寻找最长边
        {                        // 若不存在负环则可以确定源点到 每个顶点的 最长距离
            flag = false;
            for (int j=0; j<tot; ++j)
            {
                if (relax(j)) flag = true;
                //if (flag == false) return false;
            }
            if (dis[ori] > fv) return true;
            if (flag == false) return false;
        }
        for (int i=0; i<tot; ++i)
        {
            if (relax(i)) return true;
        }
        return false;
    }

    int main()
    {
        while (~scanf("%d%d%d%lf", &n, &m, &fn, &fv))
        {
            tot  = 0;
            for (int i=0; i<m; ++i)
            {
                int a, b;
                double rab, cab, rba, cba;
                scanf("%d%d%f%f%f%f", &a, &b, &rab, &cab, &rba, &cba);
                edge[tot].u = a;
                edge[tot].v = b;
                edge[tot].r = rab;
                edge[tot++].c = cab;
                edge[tot].u = b;
                edge[tot].v = a;
                edge[tot].r = rba;
                edge[tot++].c = cba;
            }
            if (bellman(fn))
                printf("YES ");
            else printf("NO ");
        }
        return 0;
    }

    附标准代码:
    #include<iostream>
    using namespace std;

    int n;     //货币种数
    int m;     //兑换点数量
    int s;     //持有第s种货币
    double v;  //持有的s货币的本金

    int all;  //边总数
    double dis[101];  //s到各点的权值

    class exchange_points
    {
    public:
        int a;      //货币a
        int b;      //货币b
        double r;   //rate
        double c;   //手续费
    }exc[202];

    bool bellman(void)
    {
        memset(dis,0,sizeof(dis));      //这里与bellman的目的刚好相反。初始化为源点到各点距离无穷小
        dis[s]=v;                       //即bellman本用于找负环,求最小路径,本题是利用同样的思想找正环,求最大路径

        /*relax*/

        bool flag;
        for(int i=1;i<=n-1;i++)
        {
            flag=false;
            for(int j=0;j<all;j++)
                if(dis[exc[j].b] < (dis[exc[j].a] - exc[j].c) * exc[j].r)         //寻找最长路径
                {                                                                 //进行比较的是"某点到自身的权值"和"某点到另一点的权值"
                    dis[exc[j].b] = (dis[exc[j].a] - exc[j].c) * exc[j].r;
                    flag=true;
                }
            if(!flag)
                break;
        }

        /*Search Positive Circle*/

        for(int k=0;k<all;k++)
            if(dis[exc[k].b] < (dis[exc[k].a] - exc[k].c) * exc[k].r)           //正环能够无限松弛
                return true;

        return false;
    }

    int main(void)
    {
        int a,b;
        double rab,cab,rba,cba;   //临时变量

        while(cin>>n>>m>>s>>v)
        {
            all=0;    //注意初始化
            for(int i=0;i<m;i++)
            {
                cin>>a>>b>>rab>>cab>>rba>>cba;
                exc[all].a=a;
                exc[all].b=b;
                exc[all].r=rab;
                exc[all++].c=cab;
                exc[all].a=b;
                exc[all].b=a;
                exc[all].r=rba;
                exc[all++].c=cba;
            }

            /*Bellman-form Algorithm*/

            if(bellman())
                cout<<"YES"<<endl;
            else
                cout<<"NO"<<endl;
        }

        return 0;
    }


  • 相关阅读:
    第二次作业
    自我介绍
    《JavaScript高级程序设计》读书笔记
    三种清理浮动的方式
    简单的水平导航条
    CSS——关于列表和导航条菜单之垂直菜单制作
    css中关于超链接的部分学习心得
    dubbox分布式框架 和相关依赖
    IO操作
    POI动态生成Excel
  • 原文地址:https://www.cnblogs.com/icode-girl/p/4580370.html
Copyright © 2011-2022 走看看