POJ - 1860 (bellman最短路正权圈与负权圈判断

题意
    有多种汇币,汇币之间可以交换,这需要手续费,当你用100A币交换B币时,A到B的汇率是29.75,手续费是0.39,那么你可以得到(100 - 0.39) * 29.75 = 2963.3975 B币。问s币的金额经过交换最终得到的s币金额数能否增加 货币的交换是可以重复多次的,所以我们需要找出是否存在正权回路,且最后得到的s金额是增加的 怎么找正权回路呢?(正权回路:在这一回路上,顶点的权值能不断增加即能一直进行松弛)
Sample Input

    3 2 1 20.0
    1 2 1.00 1.00 1.00 1.00
    2 3 1.10 1.00 1.10 1.00

即求是否存在一条可以无限松弛的正权回路;

bellman-ford 算法:每次循环判断所有边是否可以松弛,最糟糕情况每次只能对两个点之间边进行松弛,此时若无形成负权圈(求最短路经的情况),最多外层循环n-1(n为点的数量)次就可求出最短路,若此时仍未求出 ,则存在负权回路

//Bellman-Ford算法核心语句
for(k=1;k<=n-1;k++)  //外循环循环n-1次,n为顶点个数
    for(i=1;i<=m;i++)//内循环循环m次,m为边的个数,即枚举每一条边
        if(dis[v[i]]>dis[u[i]]+w[i])//尝试对每一条边进行松弛,与Dijkstra算法相同
            dis[v[i]]=dis[u[i]]+w[i]; 
//检测负权回路
flag=0;
for(i=1;i<=m;i++)
    if(dis[v[i]]>dis[u[i]]+w[i])
        flag=1;
if(flag==1)
    printf("此图有负权回路");

 

本题是求正权回路,方法一样,注意double比较的精度问题

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#define ll long long
#define MAXN 1000000+50
#define mst( x,a ) memset ( x ,a,sizeof ( x ) )
using namespace std;

const int inf = 0x3f3f3f3f ;

struct edge{
     int to;
     double w,mny;
};

int  ans_d[1005] ,vis[1005] ;
double ans[1005];
int main( ){
     mst ( ans,0);
     mst (vis ,0);
     int n,m ,st;
     double mny;
     vector <edge> es[1005];
     scanf( "%d%d" ,&n ,&m);
     scanf( "%d%lf" ,&st ,&mny );
     for( int i = 0; i<m ;i++){
         int a,b;
         double w,mny;
         edge e;
         scanf( "%d%d%lf%lf",&a ,&b ,&w ,&mny);
         e.to = b; e.w=w; e.mny=mny;
         es[a].push_back ( e );
         scanf("%lf%lf" ,&w ,&mny );
         e.to=a; e.w=w; e.mny=mny;
         es[b].push_back( e );
     }
     ans [st]=mny;
     for( int k=0 ;k<n ;k++ ){
        for( int i=1 ; i<=n ; i++){
            int sz=es[i].size( );
            for( int j=0 ; j<sz ; j++){
                int to=es[i][j].to;
                double w1=es[i][j].w,mny1=es[i][j].mny;
               // cout<<i<<"->"<<to<<' '<<(ans[i]-mny1)*w1<<endl;
                double cmp=(ans[i]-mny1)*w1;
                if( ans[to] < cmp ){
                  //  cout <<ans[to]<<" ";
                     ans[to] =  cmp ;
                     //cout <<ans[to] <<endl;
                    if(k == n-1){printf("YES"); return 0;}
                }
            }
        }
     }
     printf("NO");
     return 0;
}

 

转载于:https://www.cnblogs.com/-ifrush/p/10578792.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值