poj1860 Bellman-Ford

本文详细介绍了如何将经典的Bellman-Ford算法逆向应用,用于寻找图中的正向环路。通过N次松弛操作,可以在N个顶点的图中找出潜在的正向环路,确保算法的正确性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 * poj1860 Bellman_Ford
 * 是一个逆向使用bellman_ford算法的题目。原来单源最短路径的算法是避免负的环路,这里我们反过来,是求正的环路
 * BF算法的核心思想就是,单源最短路径如果存在,即不存在环路,那么在N个点的图中,我N-1次松弛一定可以存在最短路径.否则负向环路就会出现
 * 用在这里就是,N个点的图中,N-1次松弛一定可以找到潜在的正向环路
 * 因为我是从原点开始,而每条边都是双向的,那如果正向环路存在,我在正向环路里走足够多个圈,总可以实现到原点的正向回环
 * 这样初始化的时候我们把其他路径边都置为最小的0,依各个边去松弛,对于a->b的兑换,如果有v个a,假如按照rab*(va-cab)计算出来的值比原有的vb大,那么就更新vb
 * 最后像BF算法那样判断有无正向回环就行了 
 */
#include <cstdio>
#include <cstring>
int n,m,s,idx;
double v;
struct exchange{
    int a;
    int b;
    double rate;
    double fee;
}ec[101*101];

double money[101];

bool bellman_ford(){
    bool flag;
    memset(money,0,sizeof(money));
    money[s] = v;
    for(int i=0;i<n;++i){
        flag = false;
        //以j为条件边松弛其他边
        for(int j=0;j<idx;++j){
            if(money[ec[j].a]==0) continue;
            if(money[ec[j].b] < (money[ec[j].a] - ec[j].fee)*ec[j].rate){
                money[ec[j].b] = (money[ec[j].a] - ec[j].fee)*ec[j].rate;
                flag = true;
            }
        }
        if(!flag){
            break;
        }
    }
    
    for(int j=0;j<idx;++j){
        if(money[ec[j].b] < (money[ec[j].a] - ec[j].fee)*ec[j].rate){
            money[ec[j].b] = (money[ec[j].a] - ec[j].fee)*ec[j].rate;
            return true;
        }
    }
    return false;
}

int main(){
    scanf("%d%d%d%lf",&n,&m,&s,&v);
    int a,b;
    double rab,cab,rba,cba;
    idx = 0;
    while(m--){
        scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);
        ec[idx].a = a;
        ec[idx].b = b;
        ec[idx].rate = rab;
        ec[idx++].fee = cab;
        ec[idx].a = b;
        ec[idx].b = a;
        ec[idx].rate = rba;
        ec[idx++].fee = cba;
    }

    if(bellman_ford()){
        printf("YES\n");
    }
    else{
        printf("NO\n");
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值