uva 10000 - Longest Paths(bellman_ford算法过)

本文探讨了在图论中使用Bellman-Ford算法解决单源最短路问题,并通过路径转换策略求解最长路径问题。详细介绍了算法步骤、复杂度分析及特殊情况处理,同时对比了DFS算法的性能并指出其局限性。

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

这个题目太坑爹。。。昨儿用dfs狂T。
下面先来正确代码 一会儿错误代码也附上 求大神帮我看看dfs 为什么会T 我觉得复杂度一样

T了之后我就看网上说用Bellman_ford算法 也是求单源最短路的算法。但是比dijkstra强的是 图中可以有负权
不过效率真不怎么地 O(n*m)吧
可是我就奇怪的我的dfs也是 这个复杂度啊怎么就T了呢

写完以后还wa了三次 因为没有 每组数据后输出空行 其实我想的是两组之间有一个空行没想到uva居然这样。


我们现在想求最长的路 那换个思维 把路径都变成负的 不就是求最短路了么

这种算法大概就三步
第一个初始化d数组 除了源点意外都设为inf 不可达

第二步开始循环每条边。一共循环最多n-1 次 至于为什么 想下如果这个图没有环 那源点到任何一个点最多用n-1步就到了么 跟MST一个道理。。
每次循环的是边 对于每条边 (u,v,w);
如果的d[u]!=inf 也就是说已经到过这个点了。 并且 d【u】+w
那么就更新dv 网上称这种更新为 松弛。

这样完成后 就得到了 虽然本题不需要 但是还是要考虑一下如果这个全存在回路呢?
如果这个回路权值是正的 也就是说整条回路权值总和大于0 那么一定不会在这里死循环。
如果回路权值是负的 那就麻烦了。每次更新的时候都会成功,这样一个点一定会一直减小。
那么怎么判断呢?

 for(int i=1; i<=edgenum; ++i)

        if(dist[edge[i].v] > dist[edge[i].u] + edge[i].weight)

        {

            flag = 0;

            break;

        }


也就是说 如果没有负权回路上面循环每一条边一定不可能再更新的。
这样这个算法就描述完成了 还有可以设置一个 ischanged 如果某次没有变化 那下次也还是不会变 直接break了 这样就是  说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;

 


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=105;
const int inf=1<<15;
int n,s;
int map[maxn][maxn];
int d[maxn];

void Bellman_ford()
{
    //第一次写Bellman_ford 首先要初始化d数组
    int i,j,k;
    for(i=1;i<=n;++i)
    d[i]=inf;
    d[s]=0;
    bool ischanged=1;
    for(k=1;k<n && ischanged;++k)//最多松弛n-1次 因为一共n个点 如果没有回路 s到任何一个点做多n-1条边
    {
        ischanged=0;
        for(i=1;i<=n;++i)
        {
            for(j=1;j<=n;++j)
            {
                if(map[i][j]!=0 && d[i]!=inf && d[i]+map[i][j]<d[j])
                {
                    ischanged=1;
                    d[j]=d[i]+map[i][j];
                }
            }
        }
    }
}


int main()
{
    int i,j,a,b,ca=1;
    while(scanf("%d",&n),n)
    {
        scanf("%d",&s);
        memset(map,0,sizeof(map));
        memset(d,0,sizeof(d));
        while(scanf("%d%d",&a,&b),a+b)
        {
            map[a][b]=-1;
        }

        Bellman_ford();

        int ans=10000,index;
        for(i=1;i<=n;++i)
        {
            if(d[i]<ans)
            {
                ans=d[i];
                index=i;
            }
        }

        printf("Case %d: The longest path from %d has length %d, finishing at %d.\n\n",ca++,s,-ans,index);
    }
    return 0;
}


/* dfs方法! 尼玛T了!!!
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=105;
int n,s;
int map[maxn][maxn];
int len[maxn];

inline void in(int &a)
{
    char ch;
    while(ch = getchar(), ch < '0' || ch > '9');
    a = ch - '0';
    while(ch = getchar(), ch >= '0' && ch <= '9')
    {
        a = a * 10 + ch - '0';
    }
    return;
}

void dfs(int v)
{
    for(int i=1;i<=n;++i)
    {
        if(map[v][i])
        {
            if(len[v]+1>len[i])
            len[i]=len[v]+1;
            dfs(i);
        }
    }
}

int main()
{
    int i,j,a,b,ca=1;
    while(true)
    {
        in(n);
        if(n==0) break;
        in(s);
        memset(map,0,sizeof(map));
        memset(len,0,sizeof(len));

        while(true)
        {
            in(a);
            in(b);
            if(a==0 && b==0) break;
            map[a][b]=1;
        }

        dfs(s);

        int ans=-1,index;
        for(i=1;i<=n;++i)
        {
            if(len[i]>ans)
            {
                ans=len[i];
                index=i;
            }
        }
        if(ca!=1)
        printf("\n");

        printf("Case %d: The longest path from %d has length %d, finishing at %d.\n",ca++,s,ans,index);
    }
    return 0;
}*/


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值