学习贝尔曼算法(poj2240,1860,3259)

本文通过三个POJ题目详细介绍了如何使用Bellman-Ford算法解决含有负权边的图论问题,包括货币兑换和寻找是否存在负权环等问题。

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

利用这三个题目学习理解了一下bellman——ford 算法


poj2240:给出不同货币之间的汇率,求是否可以通过货币的多次兑换使得最终得到的货币比开始时多。其实就是求是否存在无限增大的环。

#include <iostream>
#include <string>
#include <string.h>
#include <cstdio>
using namespace std;
const int maxn=10000;
int V,E;
int n,m;
double d[maxn];
typedef struct  edge
{
    int from,to;
    double cost ;
};
struct  edge es[maxn];
char s1[1000][1000],s2[1000],s3[1000];
bool bellman_ford()
{
    for(int i=0; i<n; i++) d[i]=0;
    d[0]=1;
    for(int i=0; i<n; i++)
    {
        for(int j=0;j<m;j++)
        {
            edge e = es[j];
            if(d[e.to]<d[e.from]*e.cost)
            {
                d[e.to]=d[e.from]*e.cost;
            }
        }
    }
    for(int i=0; i<m; i++)
    {
        edge e = es[i];

        if(d[e.to]<d[e.from]*e.cost)
        {

            return true;
        }
    }
    return false;
}
int main ()
{
    int kase=1;
    while(scanf("%d",&n)!=EOF&&n)
    {
        E=0;
        memset(s1,0,sizeof(s1));
        for(int i=0; i<n; i++)
        {
            scanf("%s",s1[i]);
        }
        scanf("%d\n",&m);
        double rate;;
        for(int i=0; i<m; i++)
        {
            scanf("%s %lf %s",s2,&rate,s3);
            int k,l;
            for(int k=0; k<n; k++)
            {
                if(!strcmp(s1[k],s2))
                {
                    es[E].from=k;
                    break;
                }
            }
            for(int k=0; k<n; k++)
            {
                if(!strcmp(s1[k],s3))
                {
                    es[E].to=k;
                    break;
                }
            }
            es[E].cost=rate;
            E++;
        }
//        for(int i=0;i<E;i++)
//        {
//            printf("%d %lf %d\n" ,es[i].from,es[i].cost,es[i].to);
//        }
        if(bellman_ford()) printf("Case %d: Yes\n",kase++);
        else printf("Case %d: No\n",kase++);
    }

    return 0;
}

poj 1860:和上一题差不多,也是求给出汇率,求是否存在无限增大的环。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=105;
const int E=205;
const double MAX=99999999;
struct Edge
{
    int beg;
    int end;
    double r,c;
};
Edge edge[E];
double mindis[N];
int n,m,e,fn;
double fv;
void addedge(int beg,int end,double r,double c)
{
     edge[e].beg=beg;
      edge[e].end=end;
       edge[e].r=r;
        edge[e].c=c;
        ++e;
}
bool relax (int pe)
{
    double t=(mindis[edge[pe].beg]-edge[pe].c)*edge[pe].r;
    if(t>mindis[edge[pe].end])
    {
        mindis[edge[pe].end]=t;
        return true;
    }
    return false;
}
bool bellman_ford()
{
    bool flag;
    for(int i=0;i<n;i++) mindis[i]=0.0;
    mindis[fn]=fv;
    for(int i=0;i<n-1;i++)
    {
        flag=false;
        for(int j=0;j<e;j++)
        {
            if(relax(j)) flag=true;
        }
        if(mindis[fn]>fv) return true;
        if(!flag) return false;
    }
    for(int i=0;i<e;i++)
    {
        if(relax(i)) return true;
    }
    return false;
}
int main ()
{
    int beg,end;
    double r1,r2,c1,c2;
    scanf("%d%d%d%lf",&n,&m,&fn,&fv);
    --fn;
    e=0;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%lf%lf%lf%lf",&beg,&end,&r1,&c1,&r2,&c2);
        --beg;
        --end;
        addedge(beg,end,r1,c1);
        addedge(end,beg,r2,c2);
    }
    bool ans=bellman_ford();
    if(ans) printf("YES\n");
    else printf("NO\n");
    return 0;
}

poj 3259:题意大概是,虫洞:农夫约翰有F个农场,每个农场有N块地,其间有M条路,W条时光隧道(时间倒流)。问是否可能回到过去?

#include<cstdio>  
#include<cstring>  
#include<algorithm>  
#include<iostream>  
using namespace std;  
int map[505][505],n,m,k,num=0;  
int floyd()  
{  
    int i,j,k,f=0;  
    for(k=1;k<=n;k++)  
        for(i=1;i<=n;i++){  
            for(j=1;j<=n;j++)  
            {  
                int t=map[i][k]+map[k][j];  
                if(map[i][j]>t)map[i][j]=t;  
                /*map[i][j]=min(map[i][j],map[i][k]+map[k][j]);*/  
            }  
            if(map[i][i]<0)return 1;  
    }  
    return f;  
}  
int main()  
{  
    int t;  
    scanf("%d",&t);  
    while(t--)  
    {  
        int i,j,a,b,c;  
        scanf("%d%d%d",&n,&m,&k);  
        memset(map,0x3f3f3f3f,sizeof(map));  
        for(i=1;i<=n;i++)map[i][i]=0;  
        for(i=1;i<=m;i++)  
        {  
            scanf("%d%d%d",&a,&b,&c);  
            if(c<map[a][b])map[a][b]=map[b][a]=c;  
        }  
        for(i=1;i<=k;i++)  
        {  
            scanf("%d%d%d",&a,&b,&c);  
            map[a][b]=-c;  
        }  
        num++;  
        int f=floyd();  
        if(!f)printf("NO\n");  
        else printf("YES\n");  
    }  
    return 0;  
} 
通过这三股题目,初步理解了一下bellman的思想,发现大多数利用bellman的时候都是存在负权回路的时候。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值